//getScript(g_base + '/scripts/jquery-1.7.1.js');
//getScript(g_base + '/scripts/jquery-ui-1.8.18.custom.js');
if (typeof(j171) == 'undefined') {
	j171 = jQuery;
}
(function(j171){
	// create document resize event: trace the window.resize & ajax request
	var oldHeight = 0;
	if (document.body) {	// avoid ie8 issue	
		oldHeight = j171(document).height();
	}
	
	var activeAjaxConnections = 0;
	j171(document).ajaxSend(function() {
		activeAjaxConnections++;
	}).ajaxComplete(function() {
		setTimeout(function() {			
			activeAjaxConnections--;
			if (activeAjaxConnections == 0) {
				// it's different with ajaxStop event
				jQuery.event.trigger("documentAjaxStop");
			}
		}, 1);		// 
		
		var newHeight = j171(document).height();
		if (newHeight != oldHeight) {
			oldHeight = newHeight;
			j171(document).triggerHandler('documentResize', ['ajax']);
		}
	});
	j171(window).on('resize', function() {
		j171(document).triggerHandler('documentResize', ['resize']);
		oldHeight = 0;
	});
	
	if (g_base_site) {		
		getScript(g_base_site + '/espirit/eap/manager/i18n.common.html?_layout=self&_skipRecord=true');
	}
})(j171);

/* submit function (override the ext function from espirit.js) */
function indexOfTitle($tabs, title) {
	var index = 0;
	var found = false;
	j171('ul:first>li', $tabs).each(function() {
		var tabtitle = j171(this).children('a').eq(0).text();
		if (tabtitle == title) {
			found = true;
			return false;
		}
		index++;
	});
	return found ? index : -1;
}
/**
 * @deprecated
 * use openMainTab or open or loadChildxxx
 * 
 * Open the url in target area
 * 
 * FIXME: remove parameter btn, target
 */
function openLink(url, target, newTargetTitle, btn) {
	if (newTargetTitle == null) {
		// cache the url
		//j171('#' + target).data('url', url);
		//j171('#' + target).load(url);
		j171(getActiveDom()).load(url);
	} else if (target == '_blank') {
		window.open(url, '_blank');
	} else {
		if (btn) {	// the link comes from btn
			newTargetTitle = getModelName(j171(btn).closest('.jform').get(0)) + ':' + newTargetTitle;
		}
		
		var $mainPanel = j171('#g_mainPanel');
		var $tabs = j171('ul:first>li', $mainPanel);
		var index = indexOfTitle($mainPanel, newTargetTitle);
		if (index >= 0 && index < $tabs.length) {
			$mainPanel.tabs("select", index);
			if (url) {
				$mainPanel.tabs("url", index, url);
			}
			$mainPanel.tabs("load", index);		// force load the context again			
		} else {
			var tab = $mainPanel.tabs("add", url, newTargetTitle);
			var selected = $mainPanel.tabs("option", "selected");
			var tabtitle = j171('a', $tabs.eq(selected)).eq(0).text();
			$mainPanel.tabs("select", $tabs.length);
			var $newTab = j171('ul:first>li', $mainPanel).eq($tabs.length);
			$newTab.data('eventSource', btn);
			$newTab.data('eventTab', tabtitle);
		}
	}
}

function openWindow(btnObj, url, winType, params) {
	if (winType == 1) {		// open in the new tab
		var $activeHref = j171('#g_mainPanel > .tabHeader .ui-tabs-selected a').eq(0);
		var tabTitle = $activeHref.text();
		var title = tabTitle + ':' + j171(btnObj).text();
		openMainTab(url, title, null, btnObj);
	} else if (winType == 2) {	// open in current tab
		j171(getActiveDom()).load(url);
	} else if (winType == 3) {	// open in the new window
		openBlank(btnObj, url, params);
	} else if (winType == 4) {	// open in current window
		window.location = url;
	} else if (winType == 5) {	// popup window
		// TODO: use j171.dialog?
		showLinkTip(null, btnObj);
	} else if (winType == 6) {	// ajax submit
		j171.ajax({
			url: url,
			data: {
				_resultCode:'$json'
			},
			success:function(data) {
				var jsonData = j171.parseJSON(data);
				if (jsonData && jsonData.error) {
					showError(jsonData.error);
				} else {
					showSuccess(getText('操作成功'), 300);
				}
			}
		});
	} else if (winType == 0) {	// self defined js
		// TODO:
	}
}

/**
 * Open the url in the blank page
 * @param url
 */
function openBlank(btnObj, url, withParam) {
	if (withParam) {
		var $btn = j171(btnObj);
		var $form = $btn.closest('.jform');
		var $selectedIds = j171("[name$='.id']:checked", $form);
		$selectedIds.each(function() {
			var $this = j171(this);
			url += '&' + $this.attr('name') + '=' + $this.val();
		});
	}
	window.open(url, '_blank');
}

function refreshCurrentTab() {
	var $mainPanel = j171('#g_mainPanel');
	var index = $mainPanel.tabs("option", "selected");
	$mainPanel.tabs("load", index);
}
/**
 * Open the url with selected id parameter in the main tab
 * 
 * @param btnObj
 * @param urlOrMethod
 * @param withParam
 */
function openMainTabFromBtn(btnObj, urlOrMethod, withParam) {
	var $btn = j171(btnObj);
	var $form = $btn.closest('.jform');
	var title = getModelName($form) + ':' + $btn.html();
	var isUrl = urlOrMethod && urlOrMethod.indexOf('.') > 0;
	var url;
	var method;
	if (isUrl) {
		url = urlOrMethod;
		method = parseURL(urlOrMethod).method;		
	} else {
		url = buildRequest(btnObj, urlOrMethod);
		method = urlOrMethod;
	}
	
	// check the custom method
	var customFunc = window[method + 'Record'];
	if (typeof customFunc == 'function') {
		return customFunc(btnObj, url);
	}
	if (withParam) {
		var $selectedIds = j171("[name$='.id']:checked", $form);
		url += $selectedIds.val();
	}
	openMainTab(url, title, null, btnObj);
}
/** 
 * Open url in 'target' tab, target is the key
 * title is identified flag of tab label
 */
function openMainTab(url, title, titleKey, eventSource) {
	var $mainPanel = j171('#g_mainPanel');
	if ($mainPanel.length == 0) {
		if (url.startsWith(g_base_site + '/espirit')) {
			url += '&_layout=espirit';
		}
		openBlank(null, url);
		return;
	}
	
	if (!title && titleKey) {
		title = getText(titleKey);
	}
	var $tabs = j171('ul:first>li', $mainPanel);
	var index = indexOfTitle($mainPanel, title);
	if (index >= 0 && index < $tabs.length) {
		var $selected = $mainPanel.children('ul').find('a').eq(index);
		$selected.data('load.tabs', url);
		var selected = $mainPanel.tabs("select", index);
		if (url) {
			$mainPanel.tabs("url", index, url);
		}
		$mainPanel.tabs("load", index);		// force load the context again
	} else {
		$mainPanel.data('titleKey', titleKey);
		var tab = $mainPanel.tabs("add", url, title);
		var selected = $mainPanel.tabs("option", "selected");
		var $oldTabLink = $tabs.eq(selected).children('a').eq(0);
		var tabtitle = $oldTabLink.text();
		$mainPanel.tabs("select", $tabs.length);
		var $newTab = j171('ul:first>li', $mainPanel).eq($tabs.length);
		$newTab.data('eventSource', eventSource);
		$newTab.data('eventTab', tabtitle);
	}
	j171("html,body").animate({scrollTop: 0}, 10);
}
function _updateTabStatus(selected) {
	var $mainPanel = j171('#g_mainPanel');
	var openedTabs = {};
	if (selected == null) {		
		selected = $mainPanel.tabs("option", "selected");
	} else {
		var $selected = j171(selected);
		selected = $selected.parent().index();
	}
	openedTabs.selected = selected;
	var tabs = [];
	openedTabs.tabs = tabs;
	$mainPanel.children('ul').children('li').each(function() {
		var $tab = j171(this).children('a').eq(0);
		var url = $tab.data('load.tabs');
		if (url) {
			var fullName = j171(this).attr('fullName');
			var newTargetTitle = $tab.text();		// $tab.attr('label')
			var tabInfo = {'fullName': fullName, 'target': newTargetTitle, 'url': url};
			tabs[tabs.length] = tabInfo;
		}
	});
	openedTabs = JSON.stringify(openedTabs);
	
	var product;
	if (typeof(g_product) == 'undefined') {
		product = '';
	} else {
		product = '/' + g_product;
	}
	//j171.cookie('openedTabs', openedTabs, {'path': g_base_site + product + '/index.html'});
	if (window.sessionStorage) {
		var sessionId = j171.cookie('JSESSIONID');
		sessionStorage.setItem('g_mainPanel_openedTabs_' + sessionId + g_site, openedTabs);
	}
}
function bindMainTab(showDefineLink) {
	var $mainPanel = j171("#g_mainPanel");
	$mainPanel.bind("tabsselect", function(event, ui) {
		if (j171(ui.tab).closest('.jtab').attr('id') == 'g_mainPanel') {			
			_updateTabStatus(ui.tab);
		}
	});
	if (showDefineLink) {
		if ($mainPanel.length > 0) {		// the page has main tab
			$mainPanel.bind("tabsload", function(event, ui) {
				showDefineLinkFunc(getActiveDom());
			});
			var $cur = getActiveDom();
			if ($cur.find('.jform').length == 0) {
				showDefineLinkFunc('body');
			} else {
				showDefineLinkFunc($cur);
			}
		} else {
			showDefineLinkFunc('body');
		}
	}
}
function showDefineLinkFunc(obj) {
	// show editor link if has permission
	j171(obj).find('.jform').each(function() {
		var $form = j171(this);
		var path = $form.attr('from') || $form.attr('action');
		if (path) {					
			var $selfDefinePage = $form.children('.selfDefineLink');
			if ($selfDefinePage.length == 0) {
				$selfDefinePage = j171('<div id="selfDefineLink" class="selfDefineLink" onclick="gotoSelfDefinePage(this)"><a title="'
						+ getText('model.espirit.eap.pagelayout.page.pageDef') + '"><div class="selfDefineIcon"></div></a></div>');
				$selfDefinePage.prependTo($form);
				
				// check if it collide with the 'min/max icon'
				var $childCtn = $form.closest('.jchildContainer');
				if ($childCtn.length > 0) {
					$childCtn.find('.ctn-max-icon').each(function() {
						if (collision(j171(this), $selfDefinePage)) {
							$selfDefinePage.css('right', '32px');
							return false;
						}
					});
				}
			}
			$selfDefinePage.show();
		}
	});
}
function gotoSelfDefinePage(obj, path) {
	if (!path) {
		var $form = j171(obj).closest('.jform');
		var fromPage = $form.attr('from');
		var path;
		if (fromPage) {
			path = fromPage;
		} else {
			path = $form.attr('action');
		}
		path = path.substring(g_base_site.length);
	}
	path = encodeURIComponent(path);
	var url = g_base_site + '/espirit/eap/pagelayout/page._addByPath.html?onlyCenter=true&path=' + path;
	//openMainTab(url, getText('action.updatePage'));
	openBlank(this, url + '&_layout=whole');
}
//now, only the main tab has the close icon
function closeTab(closeIconObj) {
	var $mainPanel = j171('#g_mainPanel');
	var $closeIconTab = j171(closeIconObj).closest('li');
	var $tabHeaderTitle = $mainPanel.children('ul').children('li');
	var closeIconTabIndex = $tabHeaderTitle.index($closeIconTab);
	
	var selected = $mainPanel.tabs("option", "selected");
	var closeCurrentTab = (closeIconTabIndex == selected);
	if (closeCurrentTab) {
		var $tabSelected = $tabHeaderTitle.eq(selected);
		var tabtile = $tabSelected.data('eventTab');		// get the title before removing tab
		var index = indexOfTitle($mainPanel, tabtile);
		if (index == -1) {
			index = 0;
		}
		$mainPanel.tabs("select", index);
	}
	j171("#g_mainPanel" ).tabs("remove" , closeIconTabIndex);
	
	_updateTabStatus();
}
/*
 * FIXME: rename it as 'activePanel', add method activeTab
 */
function getActiveDom(element) {
	var $linkTipCtn = j171('#linkTipCtn');
	if ($linkTipCtn.is(':visible')) {
		return $linkTipCtn;
	}
	
	var $mainPanel = j171('#g_mainPanel');
	if ($mainPanel.length == 0) {
		return j171('body');
	} else {
		var selected = $mainPanel.tabs("option", "selected");
		var targetPanelId = j171('ul:first>li', $mainPanel).eq(selected).children('a').attr('href');
		if (element) {
			return j171(element, getActiveDom());	// TODO: use $(targetPanelId)?
		} else if (targetPanelId) {
			return j171(targetPanelId);
		} else {
			return j171('body');
		}
	}
}

function serializeChecked($ctn, onlyFirst) {
	var params = [];
	var filter = 'tr input[type=checkbox][name$=".id"]' + (onlyFirst ? ':first' : '') + ':checked';
	$ctn.find(filter).each(function() {
		var $objs = j171(this).closest('tr').find('input,select,textarea');
		$objs.each(function(index) {
			if (index == 0) {
				return ;
			}
			
			var $this = j171(this);
			var type = this.type;
			if (type == 'checkbox' || type == 'radio') {
				if (this.checked) {
					params[$this.attr('name')] = $this.val();
				}
			} else {
				params[$this.attr('name')] = $this.val();
			}
		});
	});
	$ctn.find('input:not(tr input),select:not(tr select),textarea:not(tr textarea)').each(function() {
		var $this = j171(this);
		var tagName = this.type;
		if (tagName == 'checkbox' || tagName == 'radio') {
			if (this.checked) {
				params[$this.attr('name')] = $this.val();
			}
		} else {
			params[$this.attr('name')] = $this.val();
		}
	});
	return params;
}

function serialize($ctn, includeBlankValue, includeUnCheckBox) {
	var paramArray;
	if ($ctn.is('form')) {
		paramArray = $ctn.serializeArray();
	} else {
		// FIXME: skip the element of nested form
		//var $nestedForm = $ctn.find('.jform');
		paramArray = $ctn.find('input,select,textarea').serializeArray();
	}
	var params = {};
	for (var i = 0; i < paramArray.length; i++) {
		var param = paramArray[i];
		if (includeBlankValue || param.value != '') {
			var oldValue = params[param.name];
			if (oldValue) {
				if (j171.isArray(oldValue)) {
					oldValue[oldValue.length] = param.value;
				} else {
					var oldValues = [];
					oldValues[0] = oldValue;
					oldValues[1] = param.value;
					params[param.name] = oldValues;
				}
			} else {
				params[param.name] = param.value;
			}
		}
	}
	
	if (includeUnCheckBox) {		
		$ctn.find('input[type=checkbox]').each(function() {
			if (!this.disabled) {
				var $this = j171(this);
				var val = $this.val();
				if (val == 'true' || val == 'Y') {
					var name = $this.attr('name');
					if (this.checked) {
						params[name] = 'true';
					} else {
						params[name] = 'false';
					}
				} else if (val == '1') {
					var name = $this.attr('name');
					if (this.checked) {
						params[name] = '1';
					} else {
						params[name] = '0';
					}
				}
			}
		});
	}
	return params;
}
function ajaxSubmit($form, options) {
	if (!$form || $form.length == 0) {
		$form = j171('body');
	}
	if (!validateForm($form)) {
		return false;
	} 
	
	var tables = $form.filter('table[nameprefix]');
	if (tables.length == 0) {		
		tables = $form.find('table[nameprefix]');
	}
	tables.each(function() {
		var $table = j171(this);
		var namePrefix = $table.attr('nameprefix');
		formatTableElement($table, namePrefix);
	});
	
	var includeUnCheckBox = options.includeUnCheckBox;
	if (includeUnCheckBox == null) {
		includeUnCheckBox = true;
	}
	var params = serialize($form, options.includeBlankValue, includeUnCheckBox);
	
	if (options && options.data) {
		j171.extend(params, options.data);
	}
	var action = $form.attr('action');
	if (!action) {
		action = '' + window.location;
		// replace method to submit method
		var suffixIndex = action.lastIndexOf('.');
		var methodIndex = action.lastIndexOf('.', suffixIndex - 1);
		if (methodIndex > 0 && action.charAt(methodIndex + 1) == '_') {
			action = action.substring(0, methodIndex + 1) + action.substring(methodIndex + 2);
		}
	}
	var o = {
		url: action,
		type: 'post',
		traditional: true
	};
	j171.extend(o, options);
	o.data = params;
	j171.ajax(o);
	return true;
}
/**
 * Convert the '.jform' tag to <form> tag
 * 
 * @param $oldForm
 */
function convertToForm($oldForm) {
	var oldForm = $oldForm.get(0);
	if (oldForm.tagName == 'FORM') {
		return oldForm;
	}
	
	var $newForm = j171("<form></form>");
	j171.each(oldForm.attributes, function(index) {
		$newForm.attr(oldForm.attributes[index].name, oldForm.attributes[index].value);
	});
	$oldForm.wrap($newForm);
	$oldForm.removeAttr('class');
	return $newForm;
}
function validateForm($form) {
	if ($form.length > 0) {
		var result = {'code':true};
		$form.trigger('beforeSubmit', result);
		if (!result.code) {
			showError(getText('请修正错误'));
			if (result.$element) {				
				result.$element.focus();
			}
			return false;
		}
	}
	return true;
}
function initValidate($container) {
	if ($container.data('inited')) {
		return;
	}
	$container.data('inited', true);
	
	var $elements;
	if ($container.is('form')) {
		$emements = j171($container.get(0).elements);
	} else {
		$emements = $container.find('input,select,textarea');
	}
	$emements.each(function() {
		var genericType = this.getAttribute('genericType');
		var required = this.getAttribute('required');
		var mask = this.getAttribute('mask');
		var $this = j171(this);
		if (required || mask || genericType && (genericType == 'number' || genericType == 'price')) {
			if (genericType == 'number' || genericType == 'price') {
				$this.on('keypress', function(event) {
					if (event.charCode > 0 && !event.ctrlKey) {
						var c = event.which;
						// '0' ~ '9' and '.' ',', '-'
						var isNumberChar = c >= 48 && c <= 57 || c == 46 || c == 44 || c == 45;
						if (!isNumberChar) {
							var genericType = this.getAttribute('genericType');
							if (genericType == 'price' && (c >= 65 && c <= 90 || c >= 97 && c <= 122)) {	//	a~z || A~Z
								// TODO: check price
//								var $currency = j171(this).next('input');
//								$currency.focus();
//								$currency.trigger('focus');
//								$currency.val(String.fromCharCode(c).toUpperCase());
//								$currency.focusEnd();
							} else {				
								event.preventDefault();
								var $parent = $this.parent();
								var $errorTip = $parent.children('.errorTip');
								if ($errorTip.length == 0) {									
									var errorTip = getText('无效的数字格式');
									$errorTip = j171('<div class="errorTip">' + errorTip + '</div>');
									$errorTip.appendTo($parent);
									$errorTip.css('left', $this.position().left + $this.width() + 5);
								}
								$errorTip.show();
								setTimeout(function() {
									$errorTip.remove();
								}, 1000);
							}
						}
					}
				});
			}
			
			$this.on('blur', function(event, result) {
				var $this = j171(this);
				$this.trigger('validate');
			});
			
			$this.on('validate', function(event, result) {
				var $this = j171(this);
				if ($this.is(':hidden')) {
					return;
				}
				
				var hasError = false;
				var errorTip = '';
				var val = $this.val();
				var genericType = $this.attr('genericType');
				if (genericType == 'number') {	//|| genericType == 'price'
					if (val != '') {
						hasError = !isNumber(val);
						errorTip = getText('无效的数字格式');
					}
				}
				
				if (!hasError && $this.attr('required')) {
					if (val == '') {
						hasError = true;
						errorTip = getText('必填项');
					}
				}
				
				if (!hasError && val != '') {
					var mask = this.getAttribute('mask');
					var regExp = null;
					if (mask) {
						regExp = new RegExp(mask);
						
						if (!regExp.test(val)) {
							hasError = true;
							errorTip = getText('格式错误');
						}
					}
				}
				
				var $parent = $this.parent();
				if (hasError) {
					if (!$parent.hasClass('errorCtn')) {
						$parent.addClass('errorCtn');
					}
					if ($parent.children('.errorTip').length == 0) {
						var $errorTip = j171('<div class="errorTip">' + errorTip + '</div>');
						$errorTip.appendTo($parent);
						$errorTip.css('left', $this.position().left + $this.width() + 5);
					}
					if (result) {
						result.code = false;
						result.$element = $this;
					}
				} else {
					if ($parent.hasClass('errorCtn')) {
						$parent.removeClass('errorCtn');
						$parent.children('.errorTip').remove();
					}
				}
			});
		}
	});
	if ($container.hasClass('jform')) {
		$container.bind('beforeSubmit', function(event, result) {
			result.code = true;
			
			// validate input table
			$container.find('table[nameprefix]').each(function() {
				var $table = j171(this);
				var hasRecord = false;
				var $row;
				j171('>tbody>tr', $table).each(function() {
					$row = j171(this);
					var isBlank = !hasRecordValue($row);
					j171('input,textarea,select', $row).each(function() {
						j171(this).attr('blank', isBlank);
					});
					if (!hasRecord && !isBlank) {
						hasRecord = true;
					}
				});
				
				var required = $table.attr('required');
				if (required && !hasRecord) {
					result.code = false;
					result.$element = $row.find('input,textarea,select').eq(0);
					
					$table.parent().addClass('errorCtn');
					setTimeout(function() {
						$table.parent().removeClass('errorCtn');
					}, 1000);
				}
			});
			
			var $emements = $container.find('input:not([blank=true]),select:not([blank=true]),textarea:not([blank=true])');
			$emements.trigger('validate', result);
		});
	}
}

/**
 * ensure only one 'loading' is shown in the screen
 * 
 * @param $obj
 */
function addLoading($obj, delay) {
	var loadingFunc = function() {		
		var $loadingObj = getActiveDom().find('.loading');
		if ($loadingObj.length == 0 || !$loadingObj.is(':visible')) {
			_showLoading($obj);
		} else {
			$loadingObj.data('nextLoading', $obj);
		}
	}
	if (delay != 0) {
		delay = 200;
	}
	if (delay) {
		var timer = setTimeout(loadingFunc, delay);
		$obj.data('loadingTimer', timer);
	} else {
		loadingFunc();
	}
}
function _showLoading($obj) {
	if ($obj.length == 0) {
		return ;
	}
	
	var pos = $obj.offset();
	var width = $obj.width();
	var left = pos.left + width / 2 - 100;	// 100 is the half width of loadingCtn
	var top = pos.top + 5;
	var $loadingCtn = j171('body').children('.loadingCtn');
	if ($loadingCtn.length == 0) {
		$loadingCtn = j171('<div class="loadingCtn loading"></div>');
		j171('body').append($loadingCtn);
	}
	$loadingCtn.css({'left':left, 'top': top}).show();
	
	// the max display time of loading container
	// avoid the loading container to show always
	var timeTracer = $loadingCtn.data('timeTracer');
	if (timeTracer) {
		clearTimeout(timeTracer);
	}
	timeTracer = setTimeout(function() {
		$loadingCtn.hide();
		$loadingCtn.removeData('timeTracer');
	}, 15000);
	$loadingCtn.data('timeTracer', timeTracer);
}
function removeLoading($obj) {
	var timer = $obj.data('loadingTimer');
	if (timer) {
		clearTimeout(timer);
	}
	
	var $loadingCtn = j171('body').children('.loadingCtn');
	$loadingCtn.hide();
	
	var timeTracer = $loadingCtn.data('timeTracer');
	if (timeTracer) {
		clearTimeout(timeTracer);
		$loadingCtn.removeData('timeTracer');
	}
	
	$obj.attr('loaded', true);
	
	var $next = $obj.data('nextLoading');
	if ($next && $next.length > 0 && !$next.attr('loaded')) {
		_showLoading($next);
	}
}

function initPriceEvent(inputObj) {
	var $priceCtn = j171(inputObj).closest('.priceCtn');
	if ($priceCtn.data('inited')) {
		return;
	}
	
	$priceCtn.data('inited', true);
	var $inputs = j171('input', $priceCtn);
	var $pricCurrency = $inputs.eq(0);
	var $price = $inputs.eq(1);
	var $currency = $inputs.eq(2);
	$pricCurrency.change(function(e) {
		var $inputs = j171(this).closest('.priceCtn').children('input');
		var $pricCurrency = $inputs.eq(0);
		var $price = $inputs.eq(1);
		var $currency = $inputs.eq(2);
		var val = j171(this).val().toUpperCase();
		var index;
		for (index = 0; index < val.length; index++) {
			var c = val.charAt(index);
			// '0' ~ '9' and '.' ','
			var isNumberChar = c >= '0' && c <= '9' || c == '.' || c == ',';
			if (!isNumberChar) {
				break;
			}
		}
		var price = val.substring(0, index);
		var currency = val.substring(index);
		$price.val(price);
		$currency.val(currency);
	});
	$price.change(function(e) {
		var $inputs = j171(this).closest('.priceCtn').children('input');
		var $pricCurrency = $inputs.eq(0);
		var $price = $inputs.eq(1);
		var $currency = $inputs.eq(2);
		$pricCurrency.val($price.val() + $currency.val());
	});
	$currency.change(function(e) {
		var $inputs = j171(this).closest('.priceCtn').children('input');
		var $pricCurrency = $inputs.eq(0);
		var $price = $inputs.eq(1);
		var $currency = $inputs.eq(2);
		$pricCurrency.val($price.val() + $currency.val());
	});
}

function initAllLinkTip($tipTarget, modelMapping, withId) {
	$tipTarget.each(function() {
		var $this = j171(this);
		var modelName = null;
		var propertyName = null;
		if ($this.is('input')) {
			var name = $this.attr('name');
			if (!name) {
				// special logic for combobox
				name = $this.attr('cmbname');
			}
			if (name) {
				var beginIndex = name.indexOf('.');
				if (beginIndex > 0) {				
					var endIndex = name.indexOf('.', beginIndex + 1);
					if (endIndex > 0) {					
						modelName = name.substring(beginIndex + 1, endIndex);
						propertyName = name.substring(endIndex + 1);
					}
				}
			}
		} else {
			var txtname = $this.attr('txtname');
			var index = txtname.indexOf('.');
			if (index > 0) {
				modelName = txtname.substring(0, index);
				propertyName = txtname.substring(index + 1);
			}
		}
		
		if (modelName != null && modelMapping[modelName]) {
			var url = g_base_site + '/' + modelMapping[modelName] + '._update.html?model.' + propertyName + '=';
			initLinkTip($this, url, withId);
		}
	});
}
function initLinkTipByName(name, url, withId) {
	var $curTab = getActiveDom();
	var initCurTabLinkTip = function() {
		// TODO: optimize it
		var $tableHeader = j171('th[fullname="' + name + '"]', $curTab);
		var $tipTarget;
		if ($tableHeader.length > 0 && $tableHeader.closest('table').parent().is('.jpageinfolist')) {
			name = $tableHeader.attr('name');
			if (name.indexOf('execute.') == 0) {
				name = name.substring(8);
			}
			$tipTarget = j171('div[txtname="' + name + '"]', $curTab);
		} else {
			var isDatagrid = false;
			var $pageinfo =  j171('.jpageinfo', $curTab);
			if ($pageinfo.length == 0) {
				isDatagrid = true;
				$pageinfo =  j171('.jdatagrid table', $curTab);
			}
			var namePrefix = $pageinfo.attr('nameprefix');
			var tableColumnName = name;
			if (namePrefix && name.startsWith(namePrefix)) {
				tableColumnName = name.substring(namePrefix.length);
			}
			var targetName;
			if ($pageinfo.length == 0) {				
				targetName = 'input[type=text][name="' + name + '"],input[type=text][cmbname="' + name + '"]';
			} else if (isDatagrid) {
				targetName = 'input[type=text][name="' + tableColumnName + '"],input[type=text][cmbname="' + tableColumnName + '"]' + ',div[txtname="' + tableColumnName + '"]'
			} else {
				targetName = 'div[txtname="' + tableColumnName + '"]';
			}
			$tipTarget = j171(targetName, $curTab);
		}
		$tipTarget.each(function() {
			initLinkTip(j171(this), url, withId);
		});
	};
	initCurTabLinkTip();
	
	$curTab.on('contentChange', function() {
		initCurTabLinkTip();
	});
}
function initLinkTip($tipTarget, url, withId) {
	if ($tipTarget.length == 0) {
		return;
	}
	// check if the target element has initialized
	var linkUrl = $tipTarget.attr('linkUrl');
	if (linkUrl && linkUrl != '') {
		return;
	}
	
	$tipTarget.attr('linkUrl', url);
	if ($tipTarget.is('input')) {
		$tipTarget.on('click, keypress', function() {
			var $this = j171(this);
			if ($this.val() != '') {
				showLinkTipIcon($this, withId);
			} else {
				hideTipIcon('linkTipIcon');
			}
		});
		$tipTarget.on('mouseenter', function() {
			var $this = j171(this);
			if ($this.val() != '') {
				showLinkTipIcon($this, withId);
			}
		});
		$tipTarget.on('mouseleave', function() {
			hideTipIcon('linkTipIcon');
		});
	} else {
		if (j171.trim($tipTarget.text()) != '') {
			$tipTarget.on('click', function() {
				showLinkTipIcon(j171(this), withId);
			});
			$tipTarget.mouseenter(function() {
				showLinkTipIcon(j171(this), withId);
			}).mouseleave(function() {
				hideTipIcon('linkTipIcon');
			});
		}
	}
}
var tipTime;
function showTipIcon($obj, tipId, tipText, withId) {
	var $tipIcon = j171('#' + tipId);
	if ($tipIcon.length == 0) {
		j171('body').append(tipText);
		$tipIcon = j171('#' + tipId);
		$tipIcon.on('mouseenter', function() {
			if (tipTime) {
				clearTimeout(tipTime);
			}
		}).on('click, mouseleave', function() {
			hideTipIcon(tipId);
		});
		
		j171('#g_mainPanel').on('select.tabs', function() {
			hideTipIcon(tipId);
		})
	}
	$tipIcon.attr('withId', withId);
	
	if (tipTime) {
		clearTimeout(tipTime);
	}
	var pos = $obj.offset();
	$tipIcon.data('source', $obj);
	$tipIcon.css('left', pos.left + 3).css('top', pos.top - 2);
	$tipIcon.show();
}
function hideTipIcon(tipId) {
	var $tipIcon = j171('#' + tipId);
	tipTime = setTimeout(function() {
		$tipIcon.hide();
	}, 500);
}
function showLinkTipIcon($obj, withId) {
	var tipText = '<em id=linkTipIcon class="linkTipIcon" onclick="showLinkTip(event, this)"></em>';
	showTipIcon($obj, 'linkTipIcon', tipText, withId);
}
function showLinkTip(event, linkObj) {
	var $linkTipIcon = j171('#linkTipIcon');
	var withId = $linkTipIcon.attr('withId');
	if (withId == 'false') {
		withId = false;
	}
	var $eventSource = $linkTipIcon.data('source');
	var val;
	var rowId;
	if ($eventSource.is('input')) {
		val = $eventSource.val();
		rowId = $eventSource.closest('tr').find('[name=id]').eq(0).val();
	} else {
		val = $eventSource.text();
		rowId = $eventSource.closest('tr').find('[name=id]').eq(0).val();
	}
	if (!rowId){
		rowId = $('[name="model.id"]', getActiveDom()).val();
	}
	var linkUrl = $eventSource.attr('linkUrl');
	if (linkUrl) {
		var $linkTipCtn = j171('#linkTipCtn');
		if ($linkTipCtn.length == 0) {
			j171('body').append('<div id="linkTipCtn" class="linkTipCtn"><div class="close" onclick="closeLinkTip()"></div>'
					+ '<div id="linkTipCtnBody"></div></div>');
			$linkTipCtn = j171('#linkTipCtn');
			$linkTipCtn.draggable();
		}
		
		var maxWidth = j171(document).width() - 40;
		var pos = $eventSource.offset();
		$linkTipCtn.css({'left': 20, 'top': pos.top, 'max-width': maxWidth});
		
		var path = linkUrl + val;
		if (withId && rowId) {
			path = path + '&model.id=' + rowId;
		}
		j171.ajax({
			url: path,
			cache: false,
			beforeSend: function() {
				j171('#linkTipCtnBody').html('');
				addLoading(j171('#linkTipCtnBody'));
			},
			success: function(data) {
				var $linkTipBody = j171('#linkTipCtnBody');
				removeLoading($linkTipBody);
				$linkTipBody.html(data);
				$linkTipBody.find('.jpageinfo').css('max-width', maxWidth - 20);
				
				$linkTipCtn.center();
			}
		});
		$linkTipCtn.show();
		if (event) {			
			event.stopImmediatePropagation();
		}
		$linkTipCtn.ctn().autoClose();
	}
}
function closeLinkTip() {
	var $linkTipCtn = j171('#linkTipCtn');
	$linkTipCtn.hide();
	$linkTipCtn.children('#linkTipCtnBody').html('');
	
	// TODO: add the logic here?
	$linkTipCtn.children('.simulatedScrollBar').remove();
}

/**
 * @deprecated use openMainTab, ajaxSubmit etc
 * 
 * Submit current page to target panel and target url
 * 
 * @param {} newMethod
 * @param {} url default url comes from the panel
 * @return {}
 */
function submitPage(btn, targetUrl, targetPanel, forbidAutoClose) {
	if (j171(btn).hasClass("disabled")) {
		return;
	}
	
	var btnName = btn.getAttribute('name');
	if (btnName && (btnName.indexOf('execute.remove') >=0 
			|| btnName.indexOf('execute.delete') >=0
			|| btnName.indexOf('execute.callComplete') >=0
			|| btnName.indexOf('execute.back') >=0
			||btnName.indexOf('execute.off') >=0)){
		if (!existsSelectedItem(btn)){
			infoPleaseSelectRecord();
			return;
		}
	}
	
	// lock the button 5 seconds to avoid duplicated click
	j171(btn).addClass("disabled"); 
	setTimeout(function() {
		j171(btn).removeClass("disabled");
	}, 5000);
	
	// validate
	var $form = j171(btn).closest('.jform');
	
	if (targetPanel != null) {
		// open a new panel and show it
		var index = targetPanel.indexOf(':');
		if (index >= 0) {
			targetPanel = targetPanel.substring(index + 1);
			if ($form.length > 0) {
				if (targetUrl.indexOf('?') < 0) {
					targetUrl += '?';
				}
				// $form.serialize()
				var paramArray;
				if ($form.is('form')) {
					paramArray = $form.serializeArray();
				} else {
					paramArray = $form.find('input,select,textarea').serializeArray();
				}
				var sb = '';
				for (var i = 0; i < paramArray.length; i++) {
					var param = paramArray[i];
					if (param.value != '') {
						sb += '&' + param.name + '=' + param.value;
					}
				}
				targetUrl = targetUrl + sb;
			}
			openLink(targetUrl, targetPanel, targetPanel, btn);
		} else {
			// refresh the search container
			var $pageinfo = $form.find('.jpageinfolist:first');
			ajaxSubmit($pageinfo.find('table:last'), {
				url: targetUrl,
				success:function(data) {
					var $data = j171(data);
					if ($data.hasClass('error')) {
						showError($data.html());
					} else {
						$pageinfo.replaceWith(data);
					}
				}
			});
		}
	} else {
		var options = {
			data:{_resultCode:'$close'},
			success:function(data) {
				var $data = j171(data);
				if ($data.hasClass('error')) {
					showError($data.html());
				} else {
					closeTabPage(null, true);
				}
			}
		};
		// save form and close current panel (don't check the form tag because this kind of page hasn't dummy form
		if (j171('input[type=file]', $form).length > 0) {
			$form.attr('enctype', 'multipart/form-data');
			if (!validateForm($form)) {
				j171(btn).removeClass("disabled");
				return;
			} 
			$form.ajaxSubmit(options);
		} else {
			if (!ajaxSubmit($form, options)) {
				j171(btn).removeClass("disabled");
			}
		}
	}
}

function submitInputPage(btn, params) {
	var $form = j171(btn).closest('.jform');
	var action = $form.attr('action');
	var cancelCommit = function() {
		// unformat the table element
		var tables = $form.filter('table[nameprefix]');
		if (tables.length == 0) {		
			tables = $form.find('table[nameprefix]');
		}
		tables.each(function() {
			var $table = j171(this);
			unformatTableElement($table);
		});
		enableSubmitForm(btn);
	}
	if (!params) {
		params = {};
		params._resultCode = '$close';
	}
	if (params.action) {
		action = params.action;
		delete params['action'];
	}
	var options = {
		url: action,
		data: params,
		success:function(data) {
			var $data = j171(data);
			if ($data.hasClass('message')) {		// confirm message
				var buttons = {};
				buttons[getText('确认')] = {
					'class'	: 'blue',
					'action': function() {
						var params = {};
						params.confirmedOk = true;
						j171(btn).removeClass("disabled");
						submitInputPage(btn, params);
					}
				};
				buttons[getText('否')] = {
					'class'	: 'blue',
					'action': function(){
						var params = {};
						params.confirmedNot = true;
						j171(btn).removeClass("disabled");
						submitInputPage(btn, params);
					}
				};
				buttons[getText('取消')] = {
					'class'	: 'gray',
					'action': function(){
						cancelCommit();
					}
				};
				j171.confirm({
					title : getText('确认'),
					message : $data.html(),
					buttons : buttons
				});
			} else if ($data.hasClass('error')) {	// error message
				showError($data.html());
				cancelCommit();
			} else {
				if (params._resultCode == '$close') {					
					closeInputPage(btn, true);
				} else {
					$form.replaceWith(data);
				}
			}
		}
	};
	return _submitPage(btn, options);
}
/**
 * Submit current form to specified url
 * 
 * @param btn the click button
 * @param url the specified url, null means current form target
 * @param replaceForm replace current form with the return result
 */
function submitTo(btn, url, replaceForm) {
	if (!url) {
		var $form = j171(btn).closest('.jform');
		url = $form.attr('action');
	}
	var options = {
		url:url,
		data:{_resultCode:'$json'},
		success:function(data) {
			var $data = j171(data);
			if ($data.hasClass('error')) {
				showError($data.html());
			} else {
				showSuccess(getText('操作成功'), 300);
				if (replaceForm) {
					j171(btn).closest('.jform').replaceWith($data);
				}
			}
			j171(btn).removeClass("disabled");
		}
	};
	_submitPage(btn, options);
}
function _submitPage(btn, options) {
	var $btn = j171(btn);
	if ($btn.hasClass("disabled")) {
		return;
	}
	$btn.addClass("disabled");
	
	var $form = $btn.closest('.jform');
	// save form and close current panel (don't check the form tag because this kind of page hasn't dummy form
	if (j171('input[type=file]', $form).length > 0) {
		if (!validateForm($form)) {
			j171(btn).removeClass("disabled");
			return;
		} 
		convertToForm($form);
		$form = j171(btn).closest('.jform');
		$form.attr('enctype', 'multipart/form-data');
		$form.attr('method', 'post');
		
		// format the element name
		var tables = $form.filter('table[nameprefix]');
		if (tables.length == 0) {		
			tables = $form.find('table[nameprefix]');
		}
		tables.each(function() {
			var $table = j171(this);
			var namePrefix = $table.attr('nameprefix');
			formatTableElement($table, namePrefix);
		});
		
		var params = $form.serializeArray();
		var form = $form.get(0);
		for (i=0; i < params.length; i++) {
			if (!params[i].value) {
				// TODO: enable the disabled element when error is found
				// way2: change & restore the element name
				j171(form[params[i].name]).attr('disabled', true);
			}
      	}
		$form.ajaxSubmit(options);
	} else {
		if (!ajaxSubmit($form, options)) {
			$btn.removeClass("disabled");
		}
	}
}
function enableSubmitForm(btn) {
	var $btn = j171(btn);
	$btn.removeClass("disabled");
	
	var $form = $btn.closest('.jform');
	j171('input[disabled],select[disabled],textarea[disabled]', $form).removeAttr('disabled');
}
/**
 * 
 * @param btn
 * @param isSubmit, submit = true ==> refreshParentPage
 */
function closeInputPage(btn, isSubmit) {
	// tab page or dialog page or linkTip page
	var $dialog = j171(btn).closest('.ui-dialog-content,.linkTipCtn');
	if ($dialog.length != 0) {
		if ($dialog.is('.linkTipCtn')){
			closeLinkTip();
		} else {
			if (!isSubmit) {
				isSubmit = false;
			}
			var e = new j171.Event('closeInputPage', {data: {'success': isSubmit}});
			$dialog.dialog('close', e);			
		}
	} else {
		var $mainPanel = j171('#g_mainPanel');
		if ($mainPanel.length > 0) {			
			closeTabPage(null, isSubmit);
		} else {
			window.close();
		}
	}
	if (isSubmit) {
		showSuccess(getText('操作成功'), 300);
	}
}

/**
 * 
 * @param btn
 * @param refreshParentPage true/false
 * 		true -- call the eventSource or default function to refresh page
 */
function closeTabPage(btn, refreshParentPage) {
	var $mainPanel = j171('#g_mainPanel');
	var selected = $mainPanel.tabs("option", "selected");
	var $tabSelected = j171('ul:first>li', $mainPanel).eq(selected);
	var tabtile = $tabSelected.data('eventTab');		// get the title before removing tab
	var eventSource = $tabSelected.data('eventSource');
	j171("#g_mainPanel" ).tabs("remove" , selected);
	
	var index = indexOfTitle($mainPanel, tabtile);
	if (index == -1) {
		index = 0;
	}
	$mainPanel.tabs("select", index);
	_updateTabStatus();
	
	if (refreshParentPage) {
		if (typeof(eventSource) == "function") {
			eventSource();	// trigger 'close' event
		} else {
			// default behavior is to refresh the parent page
			// check if only load the child page
			var $form;
			if (eventSource) {			
				$form = j171(eventSource).closest('.jform');
			} else {
				// maybe, the whole page refreshed and the eventSource losed
				$form = getActiveDom().find('.jform:first');
			}
			// click the refresh button
			refreshPageinfo($form);
		}
	}
}
function refreshPageinfo($activeDom) {
	if ($activeDom == null) {
		$activeDom = getActiveDom();
	}
	var click = j171.Event("click");
	//click.data = {disableSort: true};
	var $searchBtn = $activeDom.find('.button[name=search]');
	if ($searchBtn.length > 0) {
		$searchBtn.eq(0).trigger(click);
	} else {		
		var $a = $activeDom.find('.jpageinfo .pageinfo-pagination a');
		$a.eq(0).trigger(click);
	}
}
function selectText(obj) {
	var text = j171(obj).find('.ellipsis').get(0);
	if (!text) {
		return;
	}
	
	if (j171.browser.msie) {
		var range = document.body.createTextRange();
		range.moveToElementText(text);
		range.select();
	} else if (j171.browser.mozilla || j171.browser.opera) {
		var selection = window.getSelection();
		var range = document.createRange();
		range.selectNodeContents(text);
		selection.removeAllRanges();
		selection.addRange(range);
	} else if (j171.browser.safari) {
		var selection = window.getSelection();
		selection.setBaseAndExtent(text, 0, text, 1);
	}
}
//sychronize the main table header to the resize table header
function resizeFixedHeaderTable(event) {
	var $table = j171(event.currentTarget);
	var $tr = $table.children('thead').children('tr');
	var $fixedTable = $table.closest('.fht-table-wrapper').children('.fht-thead').children('table');
	var $trFixedTable = $fixedTable.children('thead').children('tr');
	$trFixedTable.html($tr.html());			// use the new tr setting
}
function setFitText(ctnObj, isHeader) {
}

function addRecord(btn, url) {
	submitPage(btn, buildRequest(btn, 'add',url));
}
function _addRecord(btn, url) {
	var title = getModelName(j171(btn).closest('.jform')) + ':' + j171(btn).text();
	openMainTab(buildRequest(btn, '_add',url), title, null, btn);
}
function openRecord(btnObj, url, blank) {
	var $id = j171(btnObj).closest('tr').find('input[name$=id]');
	var id = $id.val();
	url = url + '?model[0].id=' + id;
	if (blank) {
		openBlank(btn, url);
	} else {		
		var title = getModelName($id.closest('.jform')) + ':' + j171(btnObj).text();
		openMainTab(url, title, null, btnObj);
	}
}
function getSelectedPageinfoIds(btnObj) {
	var $form = j171(btnObj).closest('.jform');
	var $pageinfo = $form.find('.jpageinfolist:first');
	var $tr = j171('table:last tbody>tr:not(.childContainer)', $pageinfo);
	var $id = j171('input[name$=id]', $tr);
	var params = {};
	var index = 0;
	$id.each(function() {
		if (this.checked) {
			var $this = j171(this);
			var name = $this.attr('name');
			name = name.replace(/\[\d+\]/, '[' + index++ + ']');
			params[name] = $this.val();
		}
	});
	return params;
}
function deleteListRecord(btnObj) {
	deleteRecord(btnObj);
}
function deleteRecord(btnObj) {
	if (!existsSelectedItem(btnObj)){
		infoPleaseSelectRecord();
		return;
	}
	var deleteRequest = "" + buildRequest(btnObj, 'deleteList');
	j171.confirm({
		'title'		: getText('删除'),
		'message'	: getText('你确定要删除选中的记录吗?'),
		'ok'		: function() {
			var idParams = getSelectedPageinfoIds(btnObj);
			var params = toParameters(idParams);
			if (deleteRequest.indexOf('?') > 0) {
				deleteRequest = deleteRequest + params;
			} else {
				deleteRequest = deleteRequest + '?' + params;
			}
			
			j171.ajax({
				url: deleteRequest,
				type: 'post',
				cache: false,
				success: function(data) {
					var $data = j171(data);
					if ($data.hasClass('error')) {
						showError($data.html());
					} else {
						// refresh the input form
						var $form = j171(btnObj).closest('.jform');
						searchRecord($form);
					}
				}
			});
		}
	});
}
function existsSelectedItem(btn){
	var $form = j171(btn).closest('.jform');
	var $pageinfo = $form.find('.jpageinfolist:first');
	var $tr = j171('table:last tbody>tr:not(.childContainer)', $pageinfo);
	return $tr.find('input:checked[value]').length > 0;
}
function exportRecord(btn, url) {
	var path = j171(btn).closest('.jform').attr('from');
	var end = path.length - 5;
	var begin = path.lastIndexOf('.', end - 1);
	var method = path.substring(begin + 1, end);
	var params = getSelectedPageinfoIds(btn);
	openLink(buildRequest(btn, 'export', url, '_resultCode=$noResult&method=' + method + toParameters(params)), '_blank', getText('action.export'), btn);
}
function selectAll(checkObj) {
	var checked = checkObj.checked;
	var $table = j171(checkObj).closest('.jpageinfolist').find('table:last');
	
	var $tr = $table.find('>tbody>tr:not(.childContainer)');
	j171('input[name$=id]', $tr).each(function() {
		this.checked = checked;
	});
}
/* submit function - end */

function searchRecord(btnObj) {
	var $form = j171(btnObj).closest('.jform');
	var $pageinfoHeader = j171(btnObj).closest('.pageinfo-header');
	var $pageinfo = $form.children('.jpageinfo');
	var path, params;
	if ($pageinfo.length > 0 && $pageinfoHeader.length > 0) {
		path = $pageinfo.attr('path');
		params = serialize($pageinfoHeader);
	} else {
		path = $form.attr('action');
		params = serialize($form);
	}
	params['newSearch'] = true;
	j171.ajax({
		url: path,
		type: 'post',
		data: params,
		cache: false,
		beforeSend: function() {
			addLoading($pageinfo.find('table:last tbody>tr:first'));
		},
		success: function(data) {
			removeLoading($pageinfo.find('table:last tbody>tr:first'));
			var $newPageinfo = j171(data);
			if ($pageinfo.length > 0 && $pageinfoHeader.length > 0) {
				$pageinfo.replaceWith($newPageinfo);
			} else {
				$form.replaceWith($newPageinfo);
			}
			var $pagination = $form.find('.pageinfo-header .pagination:first');
			var totalCount = Number($newPageinfo.attr('totalCount'));
			var curPageStart = totalCount == 0 ? 0 : 1;
			var curPageEnd;
			if (totalCount == 0) {
				curPageEnd = 0;
			} else {
				var pageSize = Number($newPageinfo.attr('pageSize'));
				curPageEnd = pageSize < totalCount ? pageSize : totalCount;
			}
			var maxPageNo = $newPageinfo.attr('maxPageNo');
			$pagination.attr('maxPageNo', maxPageNo);
			j171('.curPageStart', $pagination).html(curPageStart);
			j171('.curPageEnd', $pagination).html(curPageEnd);
			j171('.totalCount', $pagination).html(totalCount);
			
			var $curTab = getActiveDom();
			$curTab.trigger('contentChange');
		}
	});
}

/* top menu */
function showMenu(event, linkObj) {
	var lastHoverLi = j171(linkObj).closest('li');
	var $menuTab = lastHoverLi.closest('ul');
	$menuTab.data('lastHoverLi', lastHoverLi);
	if ($menuTab.hasClass('hover')) {		
		$menuTab.removeClass('hover');
	} else {
		$menuTab.addClass('hover');
		lastHoverLi.addClass('hover');
		stopEvent(event);
		j171('body').one('click', function() {
			var lastHoverLi = $menuTab.data('lastHoverLi');
			if (lastHoverLi) {
				lastHoverLi.removeClass('hover');
			}
			$menuTab.removeClass('hover');
		});
	}
	
	if (!$menuTab.data('inited')) {
		$menuTab.data('inited', true);
		$menuTab.children('li').mouseenter(function() {
			if ($menuTab.hasClass('hover')) {
				var lastHoverLi = $menuTab.data('lastHoverLi');
				if (lastHoverLi) {
					lastHoverLi.removeClass('hover');
				}
				lastHoverLi = j171(this);
				$menuTab.data('lastHoverLi', lastHoverLi);
				lastHoverLi.addClass('hover');
			}
		});
	}
}
function selectMenu(linkObj, href, hrefTarget, text) {
	var $menu = j171(linkObj).closest('.menu');	// menu item container
	var $menuTab = $menu.closest('.tab');		// top button to show the menu
	var $menuCtn = $menuTab.closest('.jheadermenu');	// the whole menu bar
	
	$menuCtn.find('>.selected').removeClass('selected');
	$menuTab.addClass('selected');
	openMainTab(href, text, hrefTarget, linkObj);		// open window in main tab
	
	$menu.removeClass('show');								// hide the menu
	setTimeout(function() {
		$menu.addClass('show');
	}, 100);
}
/* left menu */
function switchLeftMen(linkObj) {
	// TODO:
}

function initContainer($ctns, vertical) {
	$ctns.each(function() {
		var $ctn = j171(this);
		if ($ctn.attr('inited')) {
			return;
		}
		
		$ctn.attr('inited', true);
		if (vertical) {
			_verticalPrior($ctn);
		} else {
			_horizontalPrior($ctn);
		}
		
		var $header = $ctn.children('h3');
		if ($header.length > 0) {
			$ctn.addClass('withHeader');
			$ctn.accordion({autoHeight:false});
			
			$header.find('label').click(function() {
				var $this = j171(this);
				var $h3 = $this.parent().parent();
				$h3.next().toggle();
				$h3.children('span').toggleClass('ui-icon-triangle-1-e ui-icon-triangle-1-s');
			})
		}
	});
}

function _verticalPrior($ctn) {
	var columnCount = Number($ctn.attr('columnCount'));
	// add columns and move each element one by one
	if (columnCount > 1 && columnCount < 100) {
		var strItemWidth = $ctn.attr('itemWidth');
		var itemWidths = null;
		if (strItemWidth) {
			itemWidths = strItemWidth.split(',');
			for (var i = 0; i < itemWidths.length; i++) {
				itemWidths[i] = Number(itemWidths[i])
			}
		}
		
		var percent = Math.floor(100 / columnCount);
		var $ctnbody = $ctn.children('.jcontainer-body');
		
		var $columns = [];
		for (var i = 0; i < columnCount; i++) {
			var itemWidth = 0;
			if (itemWidths) {
				if (i >= itemWidths.length) {
					itemWidth = itemWidths[0];
				} else {
					itemWidth = itemWidths[i];
				}
			}
			var strWidth = itemWidth ? (itemWidth + 'px') : (percent + '%');
			var zIndex = columnCount - i;
			
			$columns[i] = j171('<div class="colEle jcontainer-column column' + i + '" style="width:' + strWidth + ';z-index:' + zIndex +'"></div>');
			if (i == 0) {
				$ctnbody.prepend($columns[i]);
			} else {
				$columns[i].insertAfter($columns[i - 1]);
			}
		}
		var $footerColumn = null;
		
		var count = 0;
		var $stdEle = $ctnbody.children('.stdEle');
		var $tabIndex = $("input[tabIndex]").last();
		
		var beginTabIndex = 1;
		if ($tabIndex && $tabIndex.attr('tabIndex')){
			beginTabIndex = $tabIndex.attr('tabIndex') + 1;
		}
		$stdEle.each(function() {
			var $this = j171(this);
			if ($this.is('.hide,.refEle')) {
				if ($footerColumn == null) {
					$footerColumn = j171('<div class="columnFooter"></div>');
					$ctnbody.append($footerColumn);
				}
				$this.appendTo($footerColumn);
			} else {				
				var redefined = false;
				var col = $this.attr('positionCol');
				if (col != null) {	// redefined
					col = Number(col);
					$this.appendTo($columns[col]);
				} else {
					var colIndex = count % columnCount;
					$this.appendTo($columns[colIndex]);
					count ++;
				}
				var $input = $this.find('input[type!="hidden"],select,textarea');
				$input.attr('tabIndex', beginTabIndex++);
			}
		});
	}
	$ctn.removeClass('hide');
}

function _horizontalPrior($ctn){
	var columnCount = Number($ctn.attr('columnCount'));
	var labelWidth = Number($ctn.attr('labelWidth'));
	if (labelWidth == 0) {
		labelWidth = 80;
	}
	var strItemWidth = $ctn.attr('itemWidth');
	var itemWidths = null;
	if (strItemWidth) {
		itemWidths = strItemWidth.split(',');
		for (var i = 0; i < itemWidths.length; i++) {
			itemWidths[i] = Number(itemWidths[i])
		}
	}
	
	if (columnCount > 1 && columnCount < 100) {
		var percent = Math.floor(100 / columnCount);
		var count = 0;
		var curLabelWidth;
		
		$ctn.children('.jcontainer-body').children('.stdEle:not(,.hide,.refEle)').each(function(index) {
			var $this = j171(this);
			// item total width
			var thisWidth = $this.css('width');
			var itemWidth = 0;
			if (itemWidths) {
				if (index >= itemWidths.length) {
					itemWidth = itemWidths[0];
				} else {
					itemWidth = itemWidths[index];
				}
			}
			
			// calculate the colspan according to total width and the input width
			var colspan = 1;
			if (itemWidth) {				
				if (thisWidth && thisWidth != '0px') {
					colspan = Math.ceil(toNumber(thisWidth) / itemWidth);
				} else {
					var inputWidth = $this.children('span').css('width');
					if (inputWidth && inputWidth != '0px') {
						colspan = Math.ceil((toNumber(inputWidth) + labelWidth) / itemWidth);
					}
				}
			}
			
			// check if the width is defined
			// TODO: <100, special logic for history reason
			var noDefaultWidth = columnCount < 100 && (!thisWidth || thisWidth == '0px');

			// FIXME: hardcode logic: jdatagrid ignore the columnCount setting, use 100% directly
			if (noDefaultWidth && !$this.hasClass('jdatagrid')) {
				$this.css('width', (colspan * percent) + '%'); 
			}	

			// item span width
			if (noDefaultWidth) {		// set the default width if there's not width setting
				if (!curLabelWidth) {
					curLabelWidth = $this.children('label').width();
				}
				var theItemWidth = itemWidth * colspan;
				var curItemWidth = toNumber($this.children('.span').css('width')) + curLabelWidth;
				if (itemWidth != 0 && curItemWidth != 0 && curItemWidth < theItemWidth) {
					$this.css('width', theItemWidth + 'px');
				}
			}
			
			count += colspan;
			if (count % columnCount == 0) {
				$this.after('<div class="clearBoth"></div>');
			}
		});
	} else if (columnCount == 100) {
		/*j171(window).resize(function() {
			_scaleCtn($ctn);
		});*/
	}
	$ctn.removeClass('hide');
}
function showPageinfoContainer(event, obj) {
	var $obj = j171(obj);
	var status;
	if ($obj.hasClass('ctn-min-icon')) {
		status = 0;
	} else if ($obj.hasClass('ctn-normal-icon')) {
		status = 1;
	} else {
		status = 2;
	}
	
	var $ctn = $obj.parent();
	
	if ($ctn.hasClass('ctn-max')) {				// max --> normal size or min size (status = 0,1)
		var $oldParent = $ctn.data('oldParent');
		if ($oldParent) {
			$oldParent.append($ctn);
		} else {
			var $oldNext = $ctn.data('oldNext');
			if ($oldNext) {
				$oldNext.before($ctn);
			}
		}
		$ctn.find('.selfDefineLink').show();
		j171('.rootlayout').show();
	}
	
	if (status == 0) {		// min
		$obj.attr('class', 'ctn-normal-icon');
		$obj.next().attr('class', 'ctn-max-icon');
		$ctn.removeClass('ctn-max').addClass('ctn-min');
	} else if (status == 1) {	// normal
		if ($obj.next('.ctn-max-icon').length == 0) {
			$obj.attr('class', 'ctn-max-icon');
		} else {
			$obj.attr('class', 'ctn-min-icon');
		}
		$ctn.removeClass('ctn-max ctn-min');
	} else {					// max
		// 1. keep old position
		var $next = $ctn.next();
		if ($next.length > 0) {
			$ctn.data('oldNext', $next);
		} else {
			$ctn.data('oldParent', $ctn.parent());
		}
		j171('body').append($ctn);
		// 2. change icon
		$obj.attr('class', 'ctn-normal-icon');
		$obj.prev().attr('class', 'ctn-min-icon');
		// 3. max
		$ctn.removeClass('ctn-min').addClass('ctn-max');
		$ctn.find('.selfDefineLink').hide();
		j171('.rootlayout').hide();
	}
	if (status == 2) {
		j171("html,body").animate({scrollTop: 0}, 10);
	}
	stopEvent(event);
	
	// special logic for th jpageinfo
	if ($ctn.hasClass('jpageinfo')) {
		if (status == 2) {
			var $pageinfolist = $ctn.find('.jpageinfolist');
			$pageinfolist.data('oldStyle', $pageinfolist.attr('style'));
			$pageinfolist.attr('style', '');
			var $tbody = $pageinfolist.find('.fht-tbody');
			$tbody.data('oldStyle', $tbody.attr('style'));
			$tbody.attr('style', '');
			
			var $realTable = $tbody.children('.tablelist');
			$ctn.width($realTable.width());
			$ctn.height($realTable.height());
		} else {
			var $pageinfolist = $ctn.find('.jpageinfolist');
			$pageinfolist.attr('style', $pageinfolist.data('oldStyle'));
			var $tbody = $pageinfolist.find('.fht-tbody');
			$tbody.attr('style', $tbody.data('oldStyle'));
			
			$ctn.attr('style', '');
		}
	} else {
		var $childCtns = $ctn.closest('.jchildContainer');
		var $jpageinfo = $childCtns.prev('.jpageinfo');
		var $table = $jpageinfo.find('table:last');
		_adjustTableHeight($table, $childCtns);
	}
}
function _scaleCtn($ctn) {
	var height = $ctn.height();
	if (height > 30) {
		
	}
}

function adjustListLayoutTpl() {
	var $linkTipCtnBody = j171('#linkTipCtnBody');
	var $activeTab;
	if ($linkTipCtnBody.is(':visible')) {
		$activeTab = $linkTipCtnBody;
	} else {
		var $pageCtn = j171('#pageCtn');
		if ($pageCtn.is(':visible')) {
			$activeTab = $pageCtn;
		} else {			
			$activeTab = getActiveDom(); 
		}
	}
	var $containers = $activeTab.children().eq(0).children('.jcontainer');	// form > div
	if ($containers.length == 0 || $containers.attr('adjustListLayoutTpl') == 'true') {
		return;
	}
	
	$containers.attr('adjustListLayoutTpl', 'true');
	var $searchCtn = null;
	var $butonCtn = null;
	$containers.each(function() {
		var $this = j171(this);
		var name = $this.attr('name');
		if (name.indexOf('model') >= 0 && $searchCtn == null) {
			$searchCtn = $this;
		} else if (name.indexOf('execute') >= 0 && $butonCtn == null) {
			$butonCtn = $this;
		}
	});
	
	var buttonCount = -1;
	if ($butonCtn && $butonCtn.length > 0) {
		$butonCtn.addClass('pageinfo-header')
			.addClass('dynamicButtonNav')
			.addClass('pageinfo-header-button');
		buttonCount = $butonCtn.find('.button').length;
		var $addBtn = $butonCtn.find('.button[name$="add"]');
		$addBtn.addClass('blue')
			.css('margin', '0 4px 0 1px').css('padding', '3px 8px');
	}
	var inputCount = -1;
	if ($searchCtn && $searchCtn.length > 0) {
		// use 'searchInputCtn' to identify the search container
		$searchCtn.addClass('pageinfo-header jcontainer searchInputCtn')
			.css({'float':'left','clear':'none','width':'auto'});
		inputCount = $searchCtn.find('.j-form-item').length;
		var $searchBtn = $searchCtn.find('.button[name$="search"]');
		$searchBtn.addClass('blue').css('margin-left', '8px');
		//var $advanceBtn = j171('<span onclick="showAdvanceMenu(event, this, &quot;advanceModel.&quot;)" class="button button-more"><em></em></span>');
		//$advanceBtn.insertAfter($searchBtn);
	}
	if (buttonCount >= 0 && inputCount >= 0 && (buttonCount + inputCount <= 7)) {	// show in the same line
		var $simpleSearchCtn = j171('<div class="jcontainer stdCtn stdEle simpleSearch searchInputCtn" uiType="container" style="float:left;clear:none;width:auto"></div>');
		$simpleSearchCtn.attr('name', $searchCtn.attr('name'));
		$butonCtn.find('.jcontainer-body').append($simpleSearchCtn);
		$simpleSearchCtn.append($searchCtn.find('.jcontainer-body'));
		$searchCtn.replaceWith('<div class="stdCtn stdEle"></div>');			// use a empty container as the placeholder
	}
}

/* pageinfo function */
function closeChildContainer(event, closeLinkObj) {
	var $closeLink = j171(closeLinkObj);
	var $childCtn = $closeLink.closest('.jchildContainer');
	var $ctnTr = $childCtn.data('source');
	var $pageinfo = $ctnTr.closest('.jpageinfo');
	
	$pageinfo.height('auto');
	$childCtn.hide();
}
function loadChildContainer(linkObj, show, showWinBtn) {
	var $link = j171(linkObj);
	var $tr;
	if ($link.is('tr')) {
		$tr = $link;
	} else {		
		$tr = $link.closest('tr');
	}
	if ($tr.hasClass('current')) {
		return ;
	}
	
	var $table = $link.closest('table');
	$tr.addClass('current');
	var $oldTr = $table.data('$oldTr');
	if ($oldTr) {		
		$oldTr.removeClass('current');
	}
	$table.data('$oldTr', $tr);
	
	var $pageinfo = $table.closest('.jpageinfo');
	var $childCtns = $pageinfo.next('.jchildContainer');
	var modelId = $tr.attr('modelId');
	var model = $pageinfo.attr('model');
	var links = $pageinfo.attr('links');
	var linkArray = links.split('|;|');

	// prepare children container
	if ($childCtns.length == 0) {
		$pageinfo.after('<div class="jchildContainer"></div>');
		$childCtns = $pageinfo.next('.jchildContainer'); 
	}
	loadChildContainerByLinks($childCtns, linkArray, model, modelId, $table, showWinBtn);
}

function loadChildContainerByLinks($childCtns, linkArray, model, modelId, $table, showWinBtn) {
	if (!$childCtns.hasClass('jchildContainer')) {
		$childCtns.addClass('jchildContainer');
	}
	
	// check if the link loaded in current tab
	var $curTab = getActiveDom();
	var $allChildCtns = $curTab.find('.jchildContainer');
	$allChildCtns = $allChildCtns.not($childCtns);
	var checkLinks = $childCtns.data('childLinks');
	if (!checkLinks) {
		checkLinks = [];
		for (var i = 0; i < linkArray.length; i++) {
			// skip the parameter
			var index = linkArray[i].indexOf('?');
			var checkLink = index > 0 ? linkArray[i].substring(0, index) : linkArray[i];
			checkLinks[checkLink] = true;
		}
		$childCtns.data('childLinks', checkLinks);
	}
	
	var isFirstPageInfo = $table.closest('.jpageinfo').is($curTab.find('.jpageinfo:first'));
	if (!isFirstPageInfo) {
		var allLinkLoaded = false;
		// compare each container (except itself)
		for (var j = 0; j < $allChildCtns.length; j++) {
			var $theChildCtn = $allChildCtns.eq(j);
			var links = $theChildCtn.data('childLinks');
			
			var isSame = true;
			for (var checkLink in checkLinks) {
				// check & compare each link
				if (!links[checkLink]) {
					isSame = false;
					break;
				}
			}
			
			// find duplicated container
			if (isSame) {				
				allLinkLoaded = true;
				break;
			}
		}
		
		if (allLinkLoaded) {
			// hide the empty container
			var $lastChildCtn = $allChildCtns.eq($allChildCtns.length - 1);
			var text = $lastChildCtn.children('.childContent').text();
			if (!j171.trim(text)) {
				$lastChildCtn.hide();
			}
			return;
		}
	}
	
	// check the format of children container 
	if ($childCtns.children().length == 0) {
		var btnStr;
		if (showWinBtn) {
			btnStr = '<div class="ctn-min-icon" onclick="showPageinfoContainer(event,this)" style="right:16px"></div>'
				+ '<div class="ctn-max-icon" onclick="showPageinfoContainer(event,this)" style="right:2px"></div><div class="childContent"></div>';
		} else {
			btnStr = '';
		}
		
		var	str = '<div class="jtopContainer">' + btnStr 
					+ '<div class="jchildContainer0"><div class="childContent"></div></div>'
					+ '<div class="jchildContainer1"><div class="childContent"></div></div>'
				+'</div>'
				+ '<div class="jchildContainer2">' + btnStr + '</div>';
		for (var i = 3; i < linkArray.length; i++) {
			str += '<div class="jchildContainer"' + i + '>' + btnStr + '<div>';
		}
		$childCtns.html(str);
		
		if (linkArray.length == 1) {		// special logic for one container
			$childCtns.children('.jtopContainer').hide();
			$childCtns.children('.jchildContainer2').css('padding-top', '3px');
		}
	}
	
	// keep the parent height
	var $parent = $childCtns.parent();
	while ($parent.length > 0 && $parent.children('.jpageinfo').length == 0) {
		$parent = $parent.closest('.jchildContainer').parent();
	}
	if (!$parent.hasClass('jform')) {	// TODO: hardcode logic to void the tab display error, remove it after the real reason found 		
		$parent.attr('style', 'height:' + $parent.height() + 'px;overflow:hidden');
	}
	
	_adjustTableHeight($table, $childCtns);
	
	// load the child container
	if (linkArray.length == 1) {		// special logic for one container
		var link = linkArray[0] + modelId + '&_type=' + model;
		var $childCtn = $childCtns.children('.jchildContainer2').children('.childContent');
		_loadChildContainer($childCtn, link);
	} else {
		var $topCtn = $childCtns.children('.jtopContainer');
		
		// load container
		for (var  i = 0; i < linkArray.length; i++) {
			var linkPrefix = linkArray[i];
			var index = linkPrefix.indexOf('?');
			var link;
			if (index > 0) {
				link = linkPrefix + modelId + '&_type=' + model;
			} else {
				link = linkPrefix;
			}
			var ctnClass = '.jchildContainer' + i;
			var $theChildCtn = null;
			if (i < 2) {
				$theChildCtn = $topCtn.children(ctnClass).children('.childContent');
			} else {				
				$theChildCtn = $childCtns.children(ctnClass).children('.childContent');
			}
			_loadChildContainer($theChildCtn, link);
		}
	}
}
// adjust the height of the parent container ('page refresh' changes the parent container each time)
function _adjustTableHeight($table, $childCtns) {
	var winCount = 0;
	var $theChildren = $childCtns.children();
	for (var i = 0; i < $theChildren.length; i++) {
		var $theChild = $theChildren.eq(i);
		if ($theChild.is(':visible') && !$theChild.hasClass('ctn-min')) {
			winCount++;
		}
	}
	var height;
	if (winCount > 1) {	
		height = 235;
	} else if (winCount == 1) {
		height = 350;
	} else {
		height = $table.height();
	}
	setPageinfoMaxHeight($table, height);
}
function _loadChildContainer($ctn, link) {
	if (!link) {
		return;
	}
	
	var loadingFunc = setTimeout(function() {
		$ctn.addClass('contentLoading');
	}, 200);
	$ctn.load(link, function() {
		clearTimeout(loadingFunc);
		$ctn.removeClass('contentLoading');
	});
}
function enableOverfloat($table, $tr, $childCtn, gap) {
	// rule 1: no gap between table and sub container after the container is float
	var docViewBottom = j171(window).scrollTop() + j171(window).height();
	var tableBottom = $table.offset().top + $table.height();
	var childCtnTop = docViewBottom - $childCtn.height();
	var enableFloat = false;
	if (childCtnTop < tableBottom) {
		
		// rule2: sub container can't override the clicked row
		var trBottom = $tr.offset().top + $tr.height() + gap;
		if (childCtnTop > trBottom) {
			enableFloat = true;
		}
	}
	return enableFloat;
}
function loadAllChildContainer(event, linkObj) {
	var $link = j171(linkObj);
	var $ctnIcon = $link.find('.ui-icon');
	var isOpen = $ctnIcon.hasClass('ui-icon-triangle-1-e');
	var $table = $link.closest('table');
	var $tr = $table.find('>tbody>tr:not(.childContainer)');
	if (isOpen) {
		$table.find('>tbody>tr.childContainer').hide();
		j171('>td:first .ui-icon', $tr).removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-s');
	} else {
		j171('>td:first a', $tr).each(function() {
			var $this = j171(this);
			var isOpen = $this.find('.ui-icon').hasClass('ui-icon-triangle-1-e');
			if (!isOpen) {
				$this.click();
			}
		});
	}
	$ctnIcon.toggleClass('ui-icon-triangle-1-e ui-icon-triangle-1-s');
}
/* pageinfo function - end */

/* edit table function (datagrid) */
function removeRow(linkObj) {
	var $row = j171(linkObj).closest('tr');
	var rows = $row.closest('tbody').find('>tr').length;
	if (rows > 2) {
		var $table = $row.closest('table');
		$row.remove();
		var e = new j171.Event('rowChange', {row: $row, add: false});
		$table.trigger(e);
	}
}
 
function hasRecordValue($row) {
	var hasValue = false;
	j171('input,textarea,select', $row).each(function() {
		var $this = j171(this);
		var name = $this.attr('name');
		if (name != null && name !='' && $this.val() != '') {
			var type = $this.attr('type');
			if (type == 'radio') {
				hasValue = this.checked;
			} else if (type == 'checkbox') {
				hasValue = this.checked;
			} else {				
				hasValue = true;
			}
			return false;
		}
	});
	return hasValue;
}

/**
 * Call this method to format grid name before submitting it
 * 
 * @param $table
 * @param namePrefix
 */
function formatTableElement($table, namePrefix) {
	var index = 0;
	if (namePrefix && namePrefix.charAt(namePrefix.length - 1) == '.') {
		namePrefix = namePrefix.substring(0, namePrefix.length - 1);
	}
	j171('>tbody>tr', $table).each(function() {
		var $row = j171(this);
		if (hasRecordValue($row)) {
			$row.removeClass('blankRow');
			if (namePrefix != '') {
				$row.find('[name]').each(function() {
					var $this = j171(this);
					var fullName = $this.attr('fullName');
					var name;
					if (fullName == null) {
						name = $this.attr('name');
						$this.attr('fullName', name);
					} else {
						name = fullName;
					}
					var newName = namePrefix + '[' + index + '].' + name;
					$this.attr('name', newName);
				});
			}
			index++;
		} else {
			$row.addClass('blankRow');
			j171('input,textarea,select', $row).each(function() {
				j171(this).attr('disabled', true);
			});
		}
	});
}
function unformatTableElement($table, namePrefix) {
	$table.children('tbody').children('tr').each(function() {
		var $row = j171(this);
		$row.find('input,textarea,select').each(function() {
			var $this = j171(this);
			var fullName = $this.attr('fullName');
			$this.attr('name', fullName);
			$this.removeAttr('disabled');
		});
	});
}
function addNewRow($table, initValidateEvent) {
	var $rows = j171('>tbody>tr', $table);
	var $clonedRow = $rows.eq(0).clone(true);
	$clonedRow.removeClass('templateRow');
	j171('tbody', $table).append($clonedRow);
	$clonedRow.show();
	$table.data('changed', false);
	return $clonedRow;
}

function submitImageColumnRequest(event, url, linkObj) {
	var $checkObj = j171('input:first', j171(linkObj).closest('tr'));
	var id = $checkObj.val();
	url = url + id + '&_resultCode=$json';
	j171.get(url, function(data) {
		var jsonData = j171.parseJSON(data);
		if (jsonData.error) {
			showError(jsonData.error);
			return ;
		}
		
		var $imageObj = j171(linkObj).children('img');
		var oldImagePath = $imageObj.attr('originalSrc');
		var newImagePath = format(oldImagePath, jsonData);
		$imageObj.attr('src', newImagePath);
	});
	stopEvent(event);
}
function stopEvent(event) {
	if (!event) event = window.event;
	event.cancelBubble = true;
	if (event.stopPropagation) event.stopPropagation();
}

function clickOnEnter(event, obj) {
	if (event.which == 13) {
		obj.click();
	}
}

function initTableGridEvent($table, required, sortable, stats) {
	if ($table.length > 1) {			// current tab has the higher priority
		var $curTab = getActiveDom();
		$table.each(function() {
			var $cur = $curTab.find('[fullName="' + j171(this).parent().attr('fullName') + '"]');
			if ($cur.length == 1) {
				$table = $cur.children('table');
				return false;
			}
		});
	}
	
	addNewRow($table);
	j171('>tbody>tr:first', $table).hide().find('*').filter('[name]').each(function() {
		j171(this).attr('fullName', j171(this).attr('name'));
	});
	
	var statsFunc = function(obj) {
		var $obj = j171(obj);
		var name = $obj.attr('name') || $obj.attr('txtname');
		var found = false;
		for (var i = 0; i < stats.length; i++) {
			if (stats[i] == name) {
				found = true;
				break;
			}
		}
		if (found) {
			// calculate this row
			var count = 0;
			var $td = $obj.closest('td').prevAll('td:visible');
			var index = $td.length;
			var $row = $table.children('tbody').children('tr');
			$row.each(function(rowIndex) {
				if (rowIndex > 0) {						
					var $cell = j171(this).children('td:visible').eq(index);
					var $input = $cell.find('input[type=text]');
					var theVal;
					if ($input.length == 0) {
						theVal = $cell.find('.readonly').text();
					} else {
						theVal = $input.val();
					}
					var nValue = toNumber(theVal);
					count += nValue;
				}
			});
			$table.children('tfoot').children().children().eq(index).html(count);
		}
	};
	j171('tr', $table).click(function() {
		var $oldTr = $table.data('$oldTr');
		var $this = j171(this);
		$this.addClass('selected');
		if ($oldTr != null) {
			$oldTr.removeClass('selected');
		}
		$table.data('$oldTr', $this);
	});
	$table.on('blur', 'input,textarea,select', function() {
		j171(this).parent('.jbox').removeClass('focus');
		var changed = $table.data('changed');
		if (!changed) {
			return;
		}
		var $curRow = j171(this).closest('tr');
		var $rows = j171('>tr', $curRow.closest('tbody'));
		var index = $rows.index($curRow);
		
		if ((index == $rows.length - 1) && hasRecordValue($curRow)) {
			addNewRow($table, true);
		}
	}).on('focus', 'input,textarea,select', function() {
		j171(this).parent('.jbox').addClass('focus');
	}).on('change', 'input,textarea,select,.readonly', function(event) {
		$table.data('changed', true);
		if (stats) {
			statsFunc(this);
		}
	}).on('rowChange', function(event) {
		if (stats) {
			var $row1 = $table.children('tbody').children().eq(1);
			$row1.children().each(function() {
				var $child = j171(this).find('input,textarea,select,.readonly').eq(0);
				statsFunc($child.get(0));
			});
		}
	}).on('keypress','td', function(event) {			// use up/down/left/right focus the input element
		// left: 37, up: 38, right: 39, down: 40
		var keyCode = event.keyCode;
		if (keyCode >= 37 && keyCode <= 40) {
			var $td = j171(this);
		    if (keyCode == 37) {
		    	var found = false;
		    	while (!found) {
		    		$td = $td.prev('td');
		    		found = $td.length == 0 || $td.find('input,textarea,select').length > 0;
		    	}
		    } else if (keyCode == 39) {
		    	var found = false;
		    	while (!found) {
		    		$td = $td.next('td');
		    		found = $td.length == 0 || $td.find('input,textarea,select').length > 0;
		    	}
		    } else {
		    	var $tr = $td.closest('tr');
		    	if (keyCode == 38) {
		    		$tr = $tr.prev('tr');
		    	} else {
		    		$tr = $tr.next('tr');	
		    	}
		    	var colIndex = $td.index();
		    	$td = $tr.children('td').eq(colIndex);
		    } 
		    $td.find('input,textarea,select').focus();
		}
	});
	if (required) {
		// see initValidate(), $table.attr('required') 
	}
	if (sortable) {
		$table.children('thead').find('th').eq(0).width(25);
		$table.children('tbody').sortable({
			distance: 5,
			items:'tr:not(.templateRow)'
		});
	}
}
function showCarItem(btn) {
	var $form = j171(btn).closest('.jform');
	var fromUrl = $form.attr('action');
	
	var url = g_base_site + '/espirit/common/shoppingCarItem._search.html';
	//var url = buildRequest(btn, '_addFromCar', fromUrl);
	//var url = g_base_site + '/espirit/common/rfqMatchedItem._addFromCar.html';
	//var url = g_base_site + '/espirit/common/SalesOrderMatchedItem._addFromCar.html';
	var $dialog = j171.exdialog({
		url: url,
		ok: function() {
			return addCarItemToGrid(this);
		}
	});
	$dialog.on('load', function() {
		$dialog.find('span[name=addFromCar]').hide();
	});
	var $table = j171(btn).closest('table');
	j171('#dialogCtn').data('fromUrl', fromUrl).data('sourceTable', $table);
}
function addCarItemToGrid(btn) {
	var $form = j171('#dialogCtn .jform');
	if (!existsSelectedItem($form)){
		info(getText('请选择记录!'));
		return false;
	}
	
	var $dialogCtn = j171('#dialogCtn');
	var $table = $dialogCtn.data('sourceTable');
	var url = $dialogCtn.data('fromUrl');
	var params = getSelectedPageinfoIds($form);
	var hasSeparator = url && (url.indexOf('?') >= 0);
	var callbackUrl = buildRequest($form, 'addCar', url) + (hasSeparator?'':'?') + toParameters(params);
	var properties = '';
	$table.children('tbody').children().eq(0).find('input,select,textarea,.readonly').each(function(){
		var $this = j171(this);
		var isTextModel = $this.hasClass('readonly');
		var name = isTextModel ? $this.attr('txtname') : $this.attr('name');
		properties = properties + ',' + name;
	});
	properties = properties + ',id';
	j171.ajax({
		url: callbackUrl,
		data: {
			_resultCode:'$json',
			properties: properties
		},
		success:function(data) {
			var items = j171.parseJSON(data);
			
			var $rows = $table.children('tbody').children();
			var $row = $rows.eq($rows.length - 1);
			if (hasRecordValue($row)) {
				$row = addNewRow($table);
			}
			
			for (var i = 0; i < items.length; i++) {
				var item = items[i];					
				$row.find('input,select,textarea,.readonly').each(function() {
					var $this = j171(this);
					var isTextModel = $this.hasClass('readonly');
					var name = isTextModel ? $this.attr('txtname') : $this.attr('name');
					var val = Ognl.get(item, name);		// item[name]
					if (val) {
						if (isTextModel) {
							$this.html(val);
						} else {				
							$this.val(val).next('[cmbname]').val(val);
						}
					}
				});
				// id
				var id = item['id'];
				var $id = $row.find('input[name=id]');
				if ($id.length == 0) {
					var $td = $row.children().eq(0);
					$td.append('<input type="hidden" name="id">');
					$id = $td.find('input[name=id]');
				}
				$id.val(item['id']);
				$row = addNewRow($table);
			}
			var e = new j171.Event('rowChange', {row: $row, add: true});
			$table.trigger(e);
			$dialogCtn.dialog('destroy');
		}
	})
}
/* edit table function - end */

/* initialize layout */
function initDLayout(targetEle, north, west, center, east, south) {
	if (!targetEle) {
		targetEle = 'body';
	}
	
	var classIdentities = ['ui-layout-north','ui-layout-west','ui-layout-center','ui-layout-east','ui-layout-south'];
	var classEnableFlags = [north, west, center, east, south];
	var $targetEle = j171(targetEle);
	
	// step1: apply the layout one by one
	// populate all the empty(free) div block
	var emptyBlocks = [];
	$targetEle.children('div').each(function() {
		var $this = j171(this);
		var clazz = $this.attr('class');
		
		var assignedClass = false;
		if (clazz) {			
			for (var i = 0; i < classIdentities.length; i++) {
				if (clazz.indexOf(classIdentities[i]) >= 0) {
					assignedClass = true;
					classEnableFlags[i] = false;	// class has assigned, don't check it again
					break;
				}
			}
		}
		if (!assignedClass) {
			emptyBlocks.push($this);
		}
	});
	// assign the layout element to empty blocks
	var index = -1;
	for (var i = 0; i < emptyBlocks.length; i++) {
		while (++index < classEnableFlags.length) {
			if (classEnableFlags[index]) {	
				classEnableFlags[index] = false;	// class is assigned, don't check it again
				emptyBlocks[i].addClass(classIdentities[index]);
				break;
			}
		}
	}
	
	// step2: check if all the layout exists
	for (index = 0; index < classEnableFlags.length; index++ ) {
		if (classEnableFlags[index]) {
			$targetEle.append('<div class="' + classIdentities[index] + '"></div>');
		}
	}
	// step3: create layout
	 // float the toggler button
	var adjustTogglerTimeout = null;
	var adjustToggler = function(paneName, paneElement, paneState, paneOptions, layoutName) {
		if (adjustTogglerTimeout) {
			clearTimeout(adjustTogglerTimeout);
		}
		adjustTogglerTimeout = setTimeout(function() {		// execute it after all the layout event is finished
			adjustTogglerTimeout = null;
			var $resizer = $targetEle.children('.resizer');
			if ($resizer.hasClass('resizer-west')) {				
				$resizer.css({'overflow':'','z-index':2, 'width':'2px'});
			} else {
				$resizer.css({'overflow':'','z-index':1, 'width':'2px'});
			}
			$resizer.each(function() {				
				var $toggler = j171(this).children('.toggler');
				var isVertical = $toggler.hasClass('toggler-north') || $toggler.hasClass('toggler-south');
				if (isVertical) {
					
				} else {					
					if (!paneState || !paneState.isClosed) {
						$toggler.css({'width': '9px', 'margin-left': '-1px'});
					} else {
						$toggler.css({'width': '9px', 'margin-left': '1px'});
					}
				}
			});
			
			if (!$targetEle.data('initDLayoutDone')) {
				$targetEle.data('initDLayoutDone', true);
				$targetEle.triggerHandler('initDLayoutDone');
			}
		}, 301);		// see jquery.layout-1.2.0.js, closeSlider
	};
	var resizeWestEvent = function(paneName, paneElement, paneState, paneOptions, layoutName) {
		j171(paneElement).triggerHandler('resize');
		adjustToggler(paneName, paneElement, paneState, paneOptions, layoutName);
	};
	
	//var centerWidth = $targetEle.children('.ui-layout-center').css('width');
	// create layout
	var minNorthSize = 0;
	if (north) {
		minNorthSize = toNumber($targetEle.children('.ui-layout-north').css('min-height'));
		if (minNorthSize > 0) {
			minNorthSize += 4;
		}
	}
	var minSouthSize = 0;
	if (south) {
		minSouthSize = toNumber($targetEle.children('.ui-layout-south').css('min-height'));
		if (minSouthSize > 0) {
			minSouthSize += 4;
		}
	}
	var layout = $targetEle.layout({
		defaults: {
			size: "auto",
			paneClass: "pane",
			resizerClass: "resizer",
			togglerClass: "toggler",
			buttonClass: "button",
			fxSpeed: 'fast',
			hideTogglerOnSlide: false,
			enableCursorHotkey: false
		},
		north: {
			minSize: minNorthSize,
			showOverflowOnHover: true
		},
		south: {
			minSize: minSouthSize
		},
		west: {
			size: 175,
			minSize: 130,
			maxSize: 300,
			spacing_closed: 3,
			spacing_open: 3,
			onopen_end: adjustToggler,
			onclose_end: adjustToggler,
			onresize_end: resizeWestEvent
		}
	});
	$targetEle.data('layout', layout);
	adjustToggler();
	
	var id = $targetEle.attr('id');
	if (id) {
		window[id] = layout;
	}
	
	if (west) {
		var westSelector = '.ui-layout-west';
		var $west = $targetEle.children(westSelector);
		j171('<span class="pin-button"></span><span class="close-button"></span>').prependTo($west);
		layout.addPinBtn(westSelector + " .pin-button", 'west');
		layout.addCloseBtn(westSelector + " .close-button", 'west');
	}
	return layout;
}
/* initialize layout - end */

/* initialize tabs, trigger the panel click event */
function initTabs($objs, cache, enableClose, selected, tabWidths, vertical) {
	$objs.each(function() {			
		_initTabs(j171(this), cache, enableClose, selected, tabWidths, vertical);
	});
}
function _initTabs($obj, cache, enableClose, selected, tabWidths, vertical) {
	var closeTxt = "<a href='javascript:void(0)' class='closeLink' onclick='closeTab(this)'><span class='ui-icon ui-icon-close'>" + getText("关闭") + "</span></a>";
	
	var $ul = $obj.children('ul');
	$obj.children('li').appendTo($ul);
	var id = $obj.attr('id');
	if (id == 'g_mainPanel') {		// TODO: remove this logic?
		var isDefPage = j171('#pageUpdateLayout').length > 0;
		if (!isDefPage && window.sessionStorage) {
			var sessionId = j171.cookie('JSESSIONID');
			var openedTabs = sessionStorage.getItem('g_mainPanel_openedTabs_' + sessionId + g_site);
			if (openedTabs) {
				// found the existed element
				var existedNames = [];
				$ul.children('li').each(function() {
					var fullName = j171(this).attr('fullName');
					existedNames[fullName] = 'true';
				})
				
				var jsonData = j171.parseJSON(openedTabs);
				var str = '';
				var items = jsonData.tabs;		// fullName, target, url
				for (var i = 0; i < items.length; i++) {
					var item = items[i];
					if (!existedNames[item.fullName]) {						
						str += '<li class="tabHeaderTitle stdEle withCloseLink" fullName="' + item.fullName + '">'
						+ '<a href="' + item.url + '" class="title label">' + item.target + '</a>'
						+ closeTxt
						+ '</li>';
					}
				}
				$ul.append(str);
			}
		}
	}
	
	var name = $obj.attr('fullName');
	var $tabs = $obj.tabs({
		cache: cache,
		add: function(event, ui) {
			var $this = j171(this);
			var $tab = j171(ui.tab);
			var $parent = $tab.parent();
			var titleKey = $this.data('titleKey');
			if (titleKey) {
				$tab.attr('label', titleKey);
				$this.data('titleKey', null);
			}
			$parent.addClass('tabHeaderTitle stdEle');
			$tab.addClass('title');
			if (enableClose) {
				$parent.append(closeTxt);
				$parent.addClass('withCloseLink')
			}
		},
		load: function(event, ui) {
			removeLoading(j171(ui.panel));
			var $data = j171(ui.panel).children();
			if ($data.hasClass('error')) {
				showError($data.html());
				closeTab(ui.tab);
			}
		},
		select: function(event, ui) {
			var url = j171(ui.tab).data("load.tabs" );
			if (url && !j171(ui.tab).data("cache.tabs")) {
				addLoading(j171(ui.panel));
			}
			var selected = ui.index;
			if (window.sessionStorage) {
				sessionStorage.setItem('tabselected-' + name, selected);
			}
			j171(ui.panel).trigger('click');		// active a click event to let the body catch it
			j171(ui.tab).closest('.jtab').triggerHandler('select.tabs');
		}
	});
	
	var $tabBody = $obj.children('.j-hide-display');
	$tabBody.removeClass('j-hide-display');
	if (vertical) {
		$tabs.tabs().addClass("ui-tabs-vertical ui-helper-clearfix" );
		$tabs.children("ul").children("li").removeClass("ui-corner-top").addClass("ui-corner-left");
	}
	
	$tabs.show();
	
	// bind resize event
	var oldHeight = j171(document).height();
	$tabs.on('tabsshow', function() {
		var newHeight = j171(document).height();
		if (newHeight != oldHeight) {
			oldHeight = newHeight;
			j171(document).triggerHandler('documentResize');
		}
	});
	
	/*if (enableClose) {
		$obj.on("click", "span.ui-icon-close", function() {
			closeTab(this);
		});
	}*/
	
	if (selected == -1) {
		if (window.sessionStorage) {
			selected = toNumber(sessionStorage.getItem('tabselected-' + name));
		}
		if (selected >= $obj.children('div').length) {
			selected = 0;
		}
	}
	$tabs.tabs("select", selected);
	return $tabs;
}
/* initialize tabs - end */

/* initialize pageinfo */
function _updateRecord($tr, url, id) {
	var $form = $tr.closest('.jform');
	var modelName = getModelName($form);
	var title = modelName + ':' + getText('修改');
	var titleKey = getModelKey($form) + ':修改';
	openMainTab(url + id, title, titleKey,  $tr);
}
function initPageinfo($jpageinfo, dblClickName, useWinScrollBar, showWinBtn, minWidth, emptyColWidthCount, isMockPage) {
	if ($jpageinfo.length > 1) {		// current tab has the higher priority
		var $curTab = getActiveDom();
		$jpageinfo.each(function() {
			var $cur = $curTab.find('[fullName="' + j171(this).attr('fullName') + '"]');
			if ($cur.length == 1) {
				$jpageinfo = $cur;
				return false;
			}
		});
	}
	
	var $table = $jpageinfo.find('table');
	if (minWidth) {
		$table.css('min-width', minWidth + 'px');
	}

	if (!isMockPage) {
		var foundFreeWidthColumn = emptyColWidthCount > 0;
		if (!foundFreeWidthColumn) {
			var $th = $table.children('thead').children('tr').children('th');
			$th.eq($th.length - 1).css('width', 'auto');
		} else if (emptyColWidthCount > 1) {
			// adjust the width to avoid screen flicker when calling colResizable
			var $th = $table.children('thead').children('tr').children('th');
			$th.each(function() {
				var $this = j171(this);
				var width = $this.width();
				if (width) {
					$this.width();
				}
			});
		}
		
		setTimeout(function() {
			when('j171.fn.colResizable', function() {
				_initPageinfo($jpageinfo, dblClickName, useWinScrollBar, showWinBtn);
			})
		}, 1);
	}
}
function _initPageinfo($jpageinfo, dblClickName, useWinScrollBar, showWinBtn) {	// default dblClick is '_updateRecord'
	var dblClick = window[dblClickName];
	var sort = $jpageinfo.attr('sort');
	var dir = $jpageinfo.attr('dir');
	if (sort && dir) {
		var sorts = sort.split(',');
		var dirs = dir.split(',');
		for (var i = 0; i < sorts.length; i++) {
			sort = j171.trim(sorts[i]);
			if (sort.startsWith('a.')) {
				sort = sort.substring(2);
			}
			var $sortLink = j171('table:first>thead a[sort="' + sort + '"]', $jpageinfo);
			if ($sortLink.length > 0) {
				if (dirs.length > i) {
					dir = dirs[i];
				} else {
					dir = dirs[dirs.length - 1];
				}
				$sortLink.attr('dir', dir).children('.label').append('<em class="sort ' + dir + '"></em>');
			}
		}
	}
	
	//<#-- adjust the default style of header sort -->
	var $table = j171('table:first', $jpageinfo);
	var columnCount = j171('table:first>thead>tr>th', $jpageinfo).length;
	if (columnCount > 10) {
		$jpageinfo.addClass('bigTable');
	}
	//$table.removeClass('fullWidth');
	
	//<#-- enable the resizable table -->
	var rowLen = $jpageinfo.find('table tbody').children('tr:not(.noData)').length;
	if (rowLen > 0) {
		var enableResizeCol = !$jpageinfo.hasClass('dpageinfo');
		if (enableResizeCol) {
			var $resizeTable = j171('table', $jpageinfo);
			// ensure $resizeTable is visible
			if (!$resizeTable.is(':visible')) {
				$resizeTable.closest('.jcontainer').removeClass('hide');
			}
			
			if ($resizeTable.colResizable) {
				$resizeTable.colResizable({			// TODO: low performance, 200ms
					liveDrag:false, 
					gripInnerHtml:"<div class='grip'></div>", 
					draggingClass:"dotted",
					onResize:function(event) {
						if (rowLen > 10) {
							resizeFixedHeaderTable(event);
						}
					}
				});
			}
		}
	}
	
	// show multiple table header
	var $prev = $jpageinfo.prev();
	if ($prev.is('.jtableheader')) {
		var $headTr = $jpageinfo.find('table').eq(0).children('thead').children('tr');
		var $appendHeadTr = $prev.find('.ctnEle');
		var gap = $headTr.children().length - $appendHeadTr.children().length;
		var str = '<tr>' + $appendHeadTr.html();
		for (var i = 0; i < gap; i++) {
			str += '<th></th>';
		}
		str += '</tr>';
		$appendHeadTr.append(str);
		$headTr.before(str);
		$prev.remove();
	}

	var $tr = j171('table:first>tbody>tr:not(.noData)', $jpageinfo);
	
	//<#-- add double click event for the update page -->
	if (dblClick) {
		$tr.each(function() {
			var $this = j171(this);
			if ($this.attr('disableDblClick') != 'true') {				
				$this.dblclick(function() {
					var $this = j171(this);
					var id = j171('td input[type="checkbox"]:first', $this).val();
					var url = $this.closest('.jpageinfo').attr('dblClickPath');
					dblClick($this, url, id);
				}).css('cursor','pointer');
			}
		});
	}
	
	//<#-- add click event for the link page -->
	var clickLink = $jpageinfo.attr('links');
	if (clickLink) {
		// TODO: selectedPageinfoIndex
		
		// keep the parent height until all the adjustment done
		var $parent = $jpageinfo.parent();
		var oldStyle = $parent.attr('style') || '';
		// update the tabheader after the whole page finished loading
		j171(document).on('documentAjaxStop', function() {
			$parent.attr('style', oldStyle);
			_fixTableHeaderWidth();
		});
		
		$tr.click(function() {
			loadChildContainer(this, true, showWinBtn);
		});
		if ($tr.length > 0) {			
			$tr.eq(0).click();
		} else {
			$jpageinfo.next('.jchildContainer').remove();
		}
	} else {
	    var name = $jpageinfo.attr('name');
	    if ('execute' == name){
	    	$jpageinfo.height(235);
	    }
//	    var pageinfoClass = $jpageinfo.attr('class');
//	    alert(pageinfoClass);
//	    if (pageinfoClass && pageinfoClass.substr(0,9) =='jpageinfo'){
//			$jpageinfo.height(235);
//		}
	}
	
	//<#-- adjust the cell text according the cell width -->
	var $td = $tr.find('td');
	$td.click(function() {
		selectText(this);
	});
	setTimeout(function() {		
		j171('table', $jpageinfo).find('.ellipsis').each(function() {
			var $this = j171(this);
			$this.attr('title', $this.text());
		});
	}, 20);
	
	// fix the the width of pageinfolist (table can stretch the width)
	var tableWidth = $table.width();
	var $pageinfoList = $jpageinfo.find('.jpageinfolist');
	var pageinfoListWidth = $pageinfoList.width();
	if (pageinfoListWidth && pageinfoListWidth < tableWidth) {
		$pageinfoList.width(tableWidth);
	}
	
	// trace the resize event, only one time
	var $document = j171(document);
	if (!$document.data('fixTableHeaderEvent')) {
		
		// bind the window resize event
		var resize;
		var timer;
		var delayResize = function(event, flag){
			if (flag == 'ajax') {
				//fixTableHeaderWidth(flag);
			} else {
				// resize header each 100 ms
				if (!timer) {
					timer = setTimeout(function() {
						_fixTableHeaderWidth();
						timer = null;
					}, 100);
				}
			}
		};
		$document.on('documentResize', delayResize);
		$document.data('fixTableHeaderEvent', true);
	}
	
	// create the shared scroll bar
	if (useWinScrollBar) {
		var pageinfoWidth = $jpageinfo.width();
		if (tableWidth > pageinfoWidth) {
			var $activeDom = getActiveDom();
			var $simulatedScrollBar = $activeDom.children('.simulatedScrollBar');
			if ($simulatedScrollBar.length == 0) {
				$simulatedScrollBar = j171('<div class="simulatedScrollBar" onscroll="scrollTable(this)" onmousedown="stopEvent(event)"><div></div></div>');
				$simulatedScrollBar.appendTo($activeDom);
				if ($activeDom.attr('id') == 'linkTipCtn') {	// is popup window
					$activeDom.css('padding-bottom', 20);
				}
			}
			
			var scrollTables = $simulatedScrollBar.data('scrollTables');
			if (!scrollTables) {
				scrollTables = [];
				$simulatedScrollBar.data('scrollTables', scrollTables);
			} else {
				// check & remove the invalid table reference
				for (var i = 0; i < scrollTables.length; i++) {
					if (!scrollTables[i].t.is(':visible')) {
						scrollTables.splice(i, 1);
						i--;
					}
				}
			}
			scrollTables[scrollTables.length] = {'t':$jpageinfo.find('.jpageinfolist'), 'w':tableWidth};
			// bind the tab select event, change the display status of the scroll bar
			var $tab = $jpageinfo.closest('.jtab');
			if ($tab.attr('id') != 'g_mainPanel') {				
				var hasBind = $tab.data('bindScrollEvent');
				if (!hasBind) {
					$tab.on('tabsshow', function(event, $tab) {
						adjustTableScrollbarStatus();
					});
					$tab.data('bindScrollEvent', true);
				}
			}
			adjustTableScrollbarStatus();
		}
	}
}
function _fixTableHeaderWidth() {
	var $tables = getActiveDom().find('table.fht-table-init');
	
	if ($tables.length > 0) {
		// make the width is same
		$tables.each(function() {
			var $this = j171(this);
			var $headTable = $this.closest('.jpageinfolist').find('table:first');
			var headerWidth = $headTable.width();
			if ($this.width() != headerWidth) {
				$this.width(headerWidth);
			}
		});
		
		// update the resize column (plugin colResizable.js)
		// FIXME: the resize column is not correct if don't include the following code
		// but it affects by the popup window, strange
		//j171(window).triggerHandler('resize.JColResizer');
		
		// redrawing the fixed header (plugin jquery.fixedheadertable.js)
		$tables.each(function() {
			var event = {
				currentTarget : this
			};
			resizeFixedHeaderTable(event);
		});
	}
};
function scrollTable(simulatedScrollBar) {
	var isRunning = j171(simulatedScrollBar).data('time');
	if (isRunning) {
		return;
	}
	
	setTimeout(function() {
		var $simulatedScrollBar = j171(simulatedScrollBar);
		var left = $simulatedScrollBar.scrollLeft();
		var screenWidth = $simulatedScrollBar.width();
		
		var scrollTables = $simulatedScrollBar.data('scrollTables');
		for (var i = 0; i < scrollTables.length; i++) {
			var $scrollTable = scrollTables[i].t;
			var enableLeft;
			if (left <= scrollTables[i].w - screenWidth) {
				enableLeft = left;
			} else {
				enableLeft = scrollTables[i].w - screenWidth;
			}
			if (enableLeft < 0) {
				enableLeft = 0;
			}
			$scrollTable.css('left', -enableLeft);
		};
		j171(simulatedScrollBar).removeData('running');	
	}, 100);
	j171(simulatedScrollBar).data('running', true);
}
function adjustTableScrollbarStatus() {
	var $activeDom = getActiveDom();
	var $simulatedScrollBar = $activeDom.children('.simulatedScrollBar');
	var scrollTables = $simulatedScrollBar.data('scrollTables');
	if (!scrollTables) {
		return;
	}
	
	var maxWidth = 0;
	for (var i = 0; i < scrollTables.length; i++) {
		var $scrollTable = scrollTables[i].t;
		if ($scrollTable.is(':visible')) {
			if (scrollTables[i].w > maxWidth) {
				maxWidth = scrollTables[i].w;
			}
		}
	}
	if (maxWidth == 0) {
		$simulatedScrollBar.hide();
	} else {
		$simulatedScrollBar.show();
		$simulatedScrollBar.children('div').width(maxWidth);
	}
}
function setPageinfoMaxHeight($table, maxHeight) {
	var $pageinfolist = $table.closest('.jpageinfolist');
    var pageinfoClass = $pageinfolist.attr('class');
    if (!(pageinfoClass && pageinfoClass.substr(0,9) =='jpageinfo')){
		return;
	}
	
	var tableHeight = $table.height();
	if (tableHeight >= maxHeight || $pageinfolist.height() >= maxHeight) {
		$pageinfolist.height(maxHeight);
		if (tableHeight >= maxHeight) {
			$table.fixedHeaderTable();
			
			// sync the width
			var $headTable = $pageinfolist.find('table:first');
			var headerWidth = $headTable.width();
			if ($table.width() != headerWidth) {
				$table.width(headerWidth);
			}
		}
	}
}
/* initialize pageinfo - end */

/* initialize tree box */
function onTreeCheck(e, treeId, treeNode) {
	var isAdd = treeNode.checked;
	
	var zTreeObj = this.getZTreeObj(treeId);
	var treeCtnObj = zTreeObj.setting.treeCtnObj;
	var $treeCtn = j171(treeCtnObj);
	var $treeValue = $treeCtn.next('input');
	var text = $treeCtn.html();
	var newText = treeNode.name;
	text = replace(text, newText, isAdd);
	$treeCtn.html(text.substring(1));
	
	text = $treeValue.val();
	var newText = treeNode.id;
	text = replace(text, newText, isAdd);
	$treeValue.val(text.substring(1));
}
function replace(text, newText, isAdd) {
	if (text != '') {
		text = ',' + text;
	}
	if (isAdd) {
		text += ',' + newText;
	} else {
		text = text.replace(',' + newText, '');
	}
	return text;
}
function setTreeCheckValue(treeObj, ids, labelObj) {
	if (ids == '') {
		return;
	}
	
	var idList = ids.split(',');
	var labelValue = '';
	for (var i = 0; i < idList.length; i++) {
		var node = treeObj.getNodeByParam("id", idList[i], null);
		treeObj.checkNode(node, true, false);
		labelValue += ',' + node.name;
	}
	labelObj.html(labelValue.substring(1));
}
function initTreebox(event, treeCtnObj, zNodes, treeMenuId) {
	if (!zNodes || zNodes.length == 0) {
		return;
	}
	var $treeCtn = j171(treeCtnObj);
	var $treeValue = $treeCtn.next('input');
	var $treeMenu = $treeCtn.data('treeMenu');
	if ($treeMenu == null) {
		var setting = {
			treeCtnObj: treeCtnObj,
			view: {
				selectedMulti: false,
				autoCancelSelected: false
			},
			check: {
				enable: true,
				chkboxType: {"Y" : "", "N" : ""}
			},
			data: {
				simpleData: {
					enable: true
				}
			},
			callback: {
				onCheck: onTreeCheck
			}
		};
		
		var $body = j171('body');
		// hidden the other treemenu if exists
		$body.children('ul.ztree').hide();
		
		// create new treemenu
		$body.append('<ul class="ztree lightLayer" style="padding: 5px 5px 20px;" id="' + treeMenuId + '"></ul>');
		$treeMenu = $body.children('#' + treeMenuId);
		var zTreeObj = j171.fn.zTree.init($treeMenu, setting, zNodes);
		setTreeCheckValue(zTreeObj, $treeValue.val(), $treeCtn);
		zTreeObj.expandAll(true);
		
		var p = $treeCtn.offset();
		$treeMenu.css('left', p.left + 'px').css('top', (p.top + 25) + 'px');
		var mouseInTreeArea = false;
		$treeMenu.mouseenter(function() {
			mouseInTreeArea = true;
		}).mouseleave(function() {
			mouseInTreeArea = false;
		});
		j171('body').click(function() {
			if (!mouseInTreeArea) {
				$treeMenu.hide();
			}
		});
		
		$treeCtn.data('treeMenu', $treeMenu);
	} else {
		if ($treeMenu.is(':visible')) {
			$treeMenu.hide();
		} else {
			// hidden the other treemenu if exists
			j171('body').children('ul.ztree').hide();
			
			var p = $treeCtn.offset();
			$treeMenu.css('left', p.left + 'px').css('top', (p.top + 25) + 'px');
			$treeMenu.show();
		}
	}
	 
	stopEvent(event);
}
/* initialize tree box - end */

/* initialize combo box */
// trigger the input event
function clickCombobox(event, linkObj) {
	var $comboboxCtn = j171(linkObj).closest('.jcombobox');
	var $combobox = j171(linkObj).prev('input');
	if (!$comboboxCtn.data('inited')) {
		// use the input focus event to init the combobox
		$combobox.trigger('focus');
	} else {
		// switch the status: close or search
		if ($combobox.autocomplete("widget").is(":visible")) {
			$combobox.autocomplete("close");
		} else {
			// use the input focus event to search the data
			$combobox.trigger('focus');
		}
	}
}
// convert the input box to combobox, support the tab level data cache
/**
 * NOTICE:
 * $combobox is the input object
 * 
 * Usuage: 
 * $combobox.data('comboItem'), get the selected json data
 * 
 * @param alwaysShowContent show content even no response data found 
 */
function initCombobox(event, inputObj, property, labelProperty, initData, url,
		onselect, enableFreeText, alwaysShowContent, multiple) {
	var $inputObj = j171(inputObj);
	var $comboboxCtn = $inputObj.closest('.jcombobox');
	if ($comboboxCtn.data('inited')) {
		return;
	}
	
	$comboboxCtn.data('inited', true);
	$comboboxCtn.data('property', property);
	var $curTab = getActiveDom();		// current tab share the same list cache
	// all the combobox of the same tab share the same cache
	var cache = $curTab.data('comboboxCache');
	if (!cache) {
		cache = {};
		$curTab.data('comboboxCache', cache);
	}
	if (url) {
		var comboboxCache = cache[url];
		if (!comboboxCache) {
			comboboxCache = {};
			cache[url] = comboboxCache; 
		}
		if (initData) {
			comboboxCache['1,'] = initData;
		}
	}
	var $combobox = $comboboxCtn.children('.jinput');
	var $hiddenbox = $comboboxCtn.children("input[type='hidden']");
	var pagText = $comboboxCtn.children(".jcombobox-pagination").html();
	$comboboxCtn.children(".jcombobox-pagination").remove();
	var addText = $comboboxCtn.children(".jcombobox-add").html();
	$comboboxCtn.children(".jcombobox-add").remove();
	
	var pageNo = 1;
	var maxPageNo = 1;
	var pageInfoDesc = '';
	var term = '';
	$comboboxCtn.children(".jcombobox-pagination:first").remove();
	
	var resetPageNo = function() {
		var $combomenu = $combobox.data('$combomenu');
		if ($combomenu) {
			pageNo = 1;
			var $pagination = $combomenu.find('.pagination-jcb');
			j171('.pageNo', $pagination).html(pageNo);
		}
	};
	var requestModelData = function(request, response, beforeRequest) {
		var $combomenu = $combobox.data('$combomenu');
		if ($combomenu) {
			var $pagination = $combomenu.find('.pagination-jcb');
			var theNo = j171('.pageNo', $pagination).html();
			if (theNo) {
				pageNo = theNo;
			}
		}
		var newReq = {'query':term, 'pageNo':pageNo};	// NOTICE: term --> query
		if (!beforeRequest) {			
			beforeRequest = $comboboxCtn.data('beforeRequest');
		}
		var cacheKey;
		if (beforeRequest) {
			cacheKey = beforeRequest(newReq);
		}
		if (!cacheKey){
			cacheKey = pageNo + ',' + term;
		}
		cacheKey = cacheKey.toLowerCase();

		var comboboxCache;
		if (url) {			
			comboboxCache = cache[url];
		} else {
			comboboxCache = [];
			if (initData) {
				var filterData = _filterData(initData, labelProperty, term);
				var pageinfo = {maxPageNo: initData.maxPageNo, data: filterData};
				comboboxCache[cacheKey] = pageinfo;
			}
		}
		if (cacheKey in comboboxCache) {
			var pageInfo = comboboxCache[cacheKey];
			maxPageNo = pageInfo.maxPageNo;
			pageInfoDesc = pageInfo.desc;
			response(pageInfo.data);		// the cached object is pageInfo object
			return;
		} else {
			if (cacheKey.length > 0) {
				var index = cacheKey.indexOf(',');
				while (++index < cacheKey.length) {	// check all the previous key
					var preCacheKey = cacheKey.substring(0, index);
					if (preCacheKey in comboboxCache) {
						var pageInfo = comboboxCache[preCacheKey];
						if (pageInfo.maxPageNo == 1) {
							pageInfoDesc = pageInfo.desc;
							response(_filterData(pageInfo, labelProperty, term));
							return;
						}
					}
				}
			}
		}
		
		if (!newReq.cancel) {
			var cacelShowMenu = false;
			var mouseClickCheck = function(event) {
				cacelShowMenu = true;
				response(null);		// clean the loading icon
			};
			j171(document).one('mousedown', mouseClickCheck);
			var lastXhr = j171.ajax({
				url:url,
				type:'POST',
				data:newReq,
				dataType:'json',
				success:function(pageInfo, status, xhr) {
					j171(document).off('mousedown', mouseClickCheck);
					comboboxCache[cacheKey] = pageInfo;
					var $combomenu = $combobox.data('$combomenu');
					// don't show menu again if user click the blank page and close the menu
					if (!cacelShowMenu) {
						if (xhr === lastXhr) {
							maxPageNo = pageInfo.maxPageNo;
							pageInfoDesc = pageInfo.desc;
							response(pageInfo.data);
						} else {
							response([]);
						}
					}
				}
			});
		} else {
			response([]);
		}
	};
	$combobox.autocomplete({
		minLength: 0,
		url: url,
		source: requestModelData,
		autoFocus: !enableFreeText,
		position: {offset: "-5 2"},
		select: function(event, ui) {
			var oldVal = $combobox.val();
			var newVal = Ognl.get(ui.item, labelProperty);
			if (newVal != oldVal) {
				$combobox.val(newVal);	// initialize the value for the change event
			}
			$combobox.data('comboItem', ui.item);			// store current selected data
			if (oldVal != newVal) {
				$combobox.trigger('change', [oldVal, newVal]);
			} else {
				// TODO: don't trigger this method?
				$combobox.triggerHandler('change', [oldVal, newVal]);				// Notice: it force the following change listener clean combobox value
			}
			var itemPropertyVal = Ognl.get(ui.item, property);
			// FIXME: special logic for modelSelect, dont hardcode in the future 
			if (!itemPropertyVal || getText('所有') == itemPropertyVal) {
				$hiddenbox.val('');
				$combobox.val('');
			} else {
				// no matched property, it's new label. TODO: use $hiddenbox.val(itemPropertyVal); directly?
				if (enableFreeText && !itemPropertyVal) {
					$hiddenbox.val('');
				} else {
					if (multiple) {
						$combobox.html('');
						// check if the value existed
						var foundExisted = false;
						$comboboxCtn.find('input[type=hidden]').each(function() {
							if (j171(this).val() == itemPropertyVal) {
								foundExisted = true;
							}
						});
						
						if (!foundExisted) {
							var label = Ognl.get(ui.item, labelProperty);
							var name = $combobox.attr('cmbname');
							if (name.endsWith('.id')) {
								name = name.substring(0, name.length - 3) + '[0].id';
							} else {
								name = name + '[0]';
							}
							$comboboxCtn.prepend('<div class="comboItem"><div>' + label + '</div><em onclick="removeComboItem(this)" class="blackTinyClose"/>'
									+ '<input type="hidden" name="' + name + '" value="' + itemPropertyVal + '">'
									+ '</div>');
						}
						$combobox.blur();
					} else {
						$hiddenbox.val(itemPropertyVal);
					}
				}
				if (!multiple) {
					$combobox.val(Ognl.get(ui.item, labelProperty));	// set the value again because previous change listener cleaned the value
				}
			}
			$combobox.triggerHandler('select', ui);
			
			// notify the depend object
			var affect = $combobox.attr('affect');
			if (affect) {
				var targetNames = affect.split(',');
				var currentRow = $comboboxCtn.parent().is('td');
				var selector = '';
				var delayTrigger = [];
				for (var i = 0; i < targetNames.length; i++) {
					var targetName = targetNames[i];
					var index = targetName.indexOf(':');
					var targetProperty = property;		// default filter property is current element property
					if (index > 0) {
						targetProperty = targetName.substring(index + 1);
						targetName = targetName.substring(0, index);
					}
					var $targetCombobox;
					if (currentRow) {
						$targetCombobox = $combobox.closest('tr').find('input[cmbname="' + targetName + '"]');
					} else {
						$targetCombobox = j171('input[cmbname="' + targetName + '"]');
					}
					var $targetComboboxCtn = $targetCombobox.parent();
					if (!$targetComboboxCtn.data('inited')) {
						// init the target element firstly
						var event = j171.Event("focus");
						event.data = {searchAtOnce: false};
						$targetCombobox.trigger(event);
						delayTrigger[delayTrigger.length] = {eventSource: $combobox, targetProperty: targetProperty};
					} else {
						$targetCombobox.triggerHandler('dependChange', {eventSource: $combobox, targetProperty: targetProperty})
					}
				}
				if (delayTrigger.length > 0) {					
					setTimeout(function() {
						for (var i = 0; i < delayTrigger.length; i++) {
							$targetCombobox.triggerHandler('dependChange', delayTrigger[i]);
						}
					}, 10);
				}
			}
			
			event.stopPropagation();
			return false;
		}
	});
	
	if (multiple) {
		$comboboxCtn.click(function(e) {
			if (e.target == $comboboxCtn.get(0)) {
				$combobox.focus();
			}
		});
		// sort the checked item
		$comboboxCtn.sortable({
			items: '.comboItem'
		});
		// format the checked name
		$combobox.closest('.jform').bind('beforeSubmit', function(event, result) {
			$comboboxCtn.find('.comboItem input[type=hidden]').each(function(index) {
				var $this = j171(this);
				var name = $this.attr('name');
				name = name.replace(/\[\d+\]/, '[' + index + ']');
				$this.attr('name', name);
			});
		});
	}
	var $autocomplete = $combobox.data("autocomplete");
	// Disable the default blur event to prevent autocomplete component clean the input value
	$autocomplete.menu.options.blur = function( event, ui ) {
	}
	$autocomplete._renderMenu = function(ul, items) {
		ul.zIndex(9999);
		var self = this;
		j171.each(items, function(index, item) {
			self._renderItem(ul, item );
		});
		var minWidth = $comboboxCtn.width();
		ul.css('min-width', (minWidth + 20) + 'px');
		// adjust the menu left position
		var gap = $comboboxCtn.offset().left - this.element.offset().left - 1;		// border left is 1
		this.options.position.offset = gap + ' ' + 2;								// border top + border bottom is 2
		
		// build pagination
		if (pageNo != 1 || maxPageNo != 1) {
			ul.append(pagText);
		}
		j171('input .pageNo',ul).val(pageNo);
		// build the relationship between 2 components
		var $combomenu = ul;
		$combomenu.data('$combobox', $combobox);
		$combobox.data('$combomenu', $combomenu);
		
		var $pagination = j171('.pagination-jcb', ul);
		$pagination.attr('maxPageNo', maxPageNo);
		j171('.pageNo', $pagination).html(pageNo);
		j171('.maxPageNo', $pagination).html(maxPageNo);
		j171('.pageInfoDesc', $pagination).html(pageInfoDesc);
		
		// build add link
		ul.append(addText);
		var $addArea = j171('.jcomboboxAddArea', ul);
		$addArea.data('$combobox', $combobox);
	};
	$autocomplete._renderItem = function(ul, item) {
		var val = Ognl.get(item, labelProperty);
		if (val == null || val == '') {
			val = '&nbsp;';
		}
		return j171("<li></li>")
			.data("item.autocomplete", item)
			.append("<a>" + val + "</a>")
			.appendTo(ul);
	};
	var hasLinkIcon = $comboboxCtn.children('a').length > 0;
	$autocomplete._resizeMenu = function() {
		var ul = this.menu.element;
		var width = $combobox.outerWidth();
		if (hasLinkIcon) {
			width += 21;
		}
		if (width < 180) {
			width = 180;
		}
		ul.outerWidth(width);
	};
	// override the default implement to support show menu even if no data found
	$autocomplete._response = function( content ) {
		if (content != null && alwaysShowContent || !this.options.disabled && content && content.length ) {
			content = this._normalize( content );
			var autoFocus = this.options.autoFocus;
			if (!content.length) {
				this.options.autoFocus = false;
			}
			this._suggest( content );
			this.options.autoFocus = autoFocus;
			this._trigger( "open" );
		} else {
			this.close();
		}
		this.pending--;
		if ( !this.pending ) {
			this.element.removeClass( "ui-autocomplete-loading" );
		}
	};
	$inputObj.focus(function(event) {
		// clean and reset the search keyword
		term = "";
		pageNo = 1;
		$combobox.autocomplete("search");
	});
	
	var searchAtOnce = true;
	if (event.data) {
		searchAtOnce = event.data.searchAtOnce;
	}
	if (searchAtOnce) {		
		$combobox.autocomplete("search");	//trigger it at once
	}
	
	$inputObj.bind("input.autocomplete", function() {
		var $this = j171(this);
		term = $this.val() || j171.trim($this.text());
		resetPageNo();
		$combobox.autocomplete("search");	// force search behavior to get the pagination data
	});
	if (enableFreeText) {
		var syncVal;
		if ($combobox.attr('name')) {	// sychronize the input data to hidden text
			syncVal = false;
		} else {
			syncVal = true;
		}
		$combobox.change(function(){
			if (syncVal) {
				$hiddenbox.val(j171(this).val());
			} else {
				$hiddenbox.val('');
			}
		});
	} else {
		$combobox.change(function(){
			// clean it firstly, 'select' event will reset the value
			$hiddenbox.val('');
			$combobox.val('');
		});
	}
	
	if (onselect) {
		$combobox.on('select', onselect);
	}
	$combobox.on('dependChange', function(event, data) {
		var $source = data.eventSource;
		var $sourceCtn = $source.parent('.jcombobox');
		var $sourceHiddenbox = $sourceCtn.children("input[type='hidden']");
		
		var searchVal = $sourceHiddenbox.val();
		// search it
		var oldBeforeRequest = $comboboxCtn.data('beforeRequest');
		var beforeRequest = function(newReq) {
			newReq.filterProperty = data.targetProperty;
			newReq.filter = searchVal;
			return newReq.pageNo + ',' + newReq.term + ',' + newReq.filter;
		};
		requestModelData(null, function(data) {
			if (data) {
				var labelPropertyVal = Ognl.get(data[data.length - 1], property);
				var labelVal = Ognl.get(data[data.length - 1], labelProperty);
				$hiddenbox.val(labelPropertyVal);
				$combobox.val(labelVal);
			}
		}, beforeRequest);
	});
}
function removeComboItem(obj) {
	j171(obj).closest('.comboItem').remove();
}
function _filterData(pageInfo, labelProperty, term) {
	var data = pageInfo.data;
	var pyData = pageInfo[':py.data.'+labelProperty];
	term = term.toLowerCase();
	var filterData = [];
	for (var i = 0; i < data.length; i++) {
		var val = '' + Ognl.get(data[i], labelProperty);
		val = val.toLowerCase();
		if (val.indexOf(term) >= 0 || pyData && pyData[i] && pyData[i].indexOf(term) >= 0) {
			filterData[filterData.length] = data[i];
		}
	}
	return filterData;
}

function addComboElement(linkObj, url, title) {
	if (!title) {
		title = '';
	}
	
	var $combobox = j171(linkObj).closest('.ui-autocomplete').data('$combobox');
	$combobox.autocomplete("close");
	var modelName = $combobox.closest('.stdEle').children('.label').text();
	if (modelName) {
		if (modelName.charAt(0) == '*') {
			title = modelName.substring(1) + title;
		} else {
			title = modelName + title;
		}
	}
	var eventSource = function() {
		// refresh combobox cache
		var cache = getActiveDom().data('comboboxCache');
		if (cache) {
			var $combobox = j171(linkObj).closest('.jcomboboxAddArea').data('$combobox');
			var key = $combobox.autocomplete('option', 'url');
			// TODO: clean all the cache which has the same model name
			cache[key] = {};
		}
	};
	openMainTab(url, title, null, eventSource)
}

function gotoComboPage(linkObj, event, pageNo) {
	var $pagination = j171(linkObj).closest('.pagination-jcb');
	$pagination.find('.pageNo').html(pageNo);
	var $combobox = $pagination.closest('.ui-autocomplete').data('$combobox');
	$combobox.autocomplete("search");
}

/* pagination */
function gotoPage(linkObj, event, offset, callback, parentCtnName) {
	if (parentCtnName == null) {
		parentCtnName = '.pagination';
	}
	var $pagination = j171(linkObj).closest(parentCtnName);
	var pageNo = j171('.pageNo:first', $pagination).val();
	if (pageNo == '') {
		pageNo = j171('.pageNo:first', $pagination).html();
	}
	pageNo = Number(pageNo) + offset;
	var maxPageNo = $pagination.attr('maxPageNo');
	maxPageNo = Number(maxPageNo);
	if (pageNo < 1) {
		pageNo = 1;
	}
	if (pageNo > maxPageNo) {
		pageNo = maxPageNo;
	}
	callback(linkObj, event, pageNo);
}
function gotoPageOnEnter(inputObj, callback) {
	j171(inputObj).one('keypress', function(event) {
		if (event.which == 13) {
			gotoPage(inputObj, event, 0, callback);
		}
	});
}

function gotoPageInfoPage(linkObj, event, pageNo) {
	var $pagination = j171(linkObj).closest('.pagination');
	var $form = j171(linkObj).closest('.jform');
	var $pageinfo = j171('.jpageinfo:first', $form);		// the list page
	if ($pageinfo.length == 0) {
		$pageinfo = $form;			// submit the form page
	}
	
	var sort, dir;
	if (event.data && event.data.disableSort) {
		sort = '';
		dir = '';
	} else {		
		sort = $pageinfo.attr('sort') || '';
		dir = $pageinfo.attr('dir') || '';
	}
	var pageSize = toNumber($pageinfo.attr('pageSize'));
	
	pageNo = toNumber(pageNo);
	var maxPageNo = $pageinfo.attr('maxPageNo');
	maxPageNo = toNumber(maxPageNo);
	if (pageNo > maxPageNo) {
		pageNo = maxPageNo;
	}
	if (pageNo < 1) {
		pageNo = 1;
	}
	
	var start = (pageNo - 1) * pageSize;
	var end = start + pageSize;
	var totalCount = Number(j171('.totalCount:first', $pagination).html());
	if (end > totalCount) {
		end = totalCount;
	}
	
	var path = $pageinfo.attr('path');
	if (!path) {
		path = $pageinfo.attr('action');
		if (!path) {			
			return ;
		}
	}
	if (path.indexOf('?') == -1) {
		path += '?';
	}
	path += '&start=' + start + '&limit=' + pageSize + '&sort=' + sort + '&dir=' + dir;
	
	j171.ajax({
		url: path,
		cache: false,
		beforeSend: function() {
			addLoading($pageinfo.find('table:last').find('tr:first'));
		},
		success: function(data) {
			removeLoading($pageinfo.find('table:last').find('tr:first'));
			$pageinfo.replaceWith(data);
			var $pagination = j171(linkObj).closest('.pagination');
			j171('.pageNo:first', $pagination).val(pageNo);
			if (end == 0) {
				j171('.curPageStart:first', $pagination).html(0);
			} else {				
				j171('.curPageStart:first', $pagination).html(start + 1);
			}
			j171('.curPageEnd:first', $pagination).html(end);
			
			// Notice: ensure the page is active, or use $pageinfo.closest('.ui-tabs-panel')?
			var $curTab = getActiveDom();
			$curTab.trigger('contentChange');
		}
	});
}

function sortSearch(linkObj, event) {
	var $linkObj = j171(linkObj);
	var $pagination = $linkObj.closest('.jpageinfo');
	$pagination.attr('sort', $linkObj.attr('sort'));
	var dir = $linkObj.attr('dir');
	if (dir == 'ASC' || dir == 'asc') {
		dir = 'DESC';
	} else {
		dir = 'ASC';
	}
	$pagination.attr('dir', dir);
	gotoPageInfoPage(linkObj, event, 1);
}

function gotoWebSearchPage($linkObj) {
	var href = $linkObj.attr('href');
	var pageNo = href.substring(href.lastIndexOf('/') + 1);
	var $form = $linkObj.closest('form');
	j171('.pageNo', $form).val(pageNo);
	var target = $form.attr('target');
	$form.ajaxSubmit({target:target});
}
function showReadyResult(isSearching) {
	var activeDom = getActiveDom();
	j171('#webSearchLoadingContainer .listItem', activeDom).each(function() {
		var id = this.id;
		var id = id.substring(0, id.length - 1);	//skip the last 0, see searchReadyResult
		j171('#' + id, activeDom).remove();
		j171(this).attr('id', id);
		j171('#webSearchReadyContainer', activeDom).append(j171(this));
		
		var userId = id.substring(20);		// skip 'messageItemContainer'
		j171('#webSearchNoMatch' + userId, activeDom).hide();
		j171('#webSearchMatch' + userId, activeDom).show();
	});
	j171('#webSearchLoadingContainer', activeDom).html('');
	if (!isSearching) {
		j171('.searching', activeDom).replaceWith('没有数据');
		j171('.noMatchUser', activeDom).html('无匹配');
	}
}


/* search menu button */
function showAdvanceMenu(event, btnObj, namePrefix) {
	var $btn = j171(btnObj);
	var $menu = $btn.data('advanceMenu'); 
	
	if (!$menu) {
		$menu = $btn.closest('.jform').find('.searchTemplate:first');
		$btn.data('advanceMenu', $menu);
		$menu.data('searchBtn', $btn);
		
		stopEvent(event);
		
		j171($btn).click(function(event) {
			event.stopPropagation();
		});
		j171($menu).click(function(event) {
			event.stopPropagation();
		});
		var func = function() {
			if ($menu.is(':visible')) {
				$menu.hide();
				$btn.removeClass('button-more-up');
				$btn.addClass('button-more-down');				
				j171('html').off('click', func);
			}
		};
		j171('html').on('click', func);
		
		var $simpSearchCtn = $btn.closest('.jcontainer');
		var $input = j171(':input:not(.expressionTip input)', $menu);
		if (namePrefix != '') {
			$input.each(function() {
				var $this = j171(this);
				// adjust the name prefix
				var name = $this.attr('name');
				if (name && name != '') {
					if (name.charAt(0) == ':') {
						var index = name.indexOf(':', 1);
						name = name.substring(index + 1);
					}
					
					name = namePrefix + name;
					$this.attr('name', name);
					
					// sychronize the input data
					var $simpleInput = $simpSearchCtn.find('input[name="' + name + '"]');
					if ($simpleInput.length > 0) {						
						$this.blur(function() {
							$simpleInput.val($this.val());
						});
					}
				}
				// show the placeholder
				// $this.attr('placeholder', '')
			});
		}
		//fixPlaceholderDefect($input);
	
		$input.focus(function() {
			var genericType = this.getAttribute('genericType');
			if (genericType == 'date' || genericType == 'combobox' || genericType == 'select') {
				$expressionTip.hide();
				return;
			}
			var type = this.type;
			if (type == 'checkbox' || type == 'radio') {
				$expressionTip.hide();
				return;
			}
			
			$expressionTip.data('target', j171(this));
			var p3 = j171(this).offset();
			var p4 = $menu.offset();
			$expressionTip.css('top', p3.top - p4.top - 41);
			$expressionTip.css('left', p3.left - p4.left + j171(this).width() + 8);
			explainExpression(this, $expressionTip);
			$expressionTip.show();
		}).keyup(function() {
			explainExpression(this, $expressionTip);
		})
		
		var $items = j171('>div.j-form-item', $menu);
		var length = $items.length;
		if (length > 10) {
			// 2 columns model, default is 1 colum controlled by css
			$menu.css('width', '520px');
			var count = 0;
			$items.each(function() {
				var $this = j171(this);
				if ($this.find('input,select').length == 0) {
					$this.hide();
				}
				count += 1;
				if ((count % 2) == 0) {
					$this.after('<div style="clear:both"></div>');
				}
			});
		}
		
		j171('body').append($menu);
	}
	

	var $expressionTip = $menu.children('.expressionTip');
	$expressionTip.hide();
	
	// adjust position
	var p1 = $btn.offset();
	var width = $menu.width();
	var maxWidth = j171(window).width();
	var left = p1.left;
	if (p1.left + width + 40 > maxWidth) {
		left = maxWidth - 40 - width;
		if (left < 0) {
			left = 0;
		}
	}
	$menu.css({'left': left, 'top': p1.top + 23});
	
	if ($menu.is(':visible')) {
		$btn.removeClass('button-more-up');
		$btn.addClass('button-more-down');
		$menu.hide();
	} else {
		$btn.removeClass('button-more-down');
		$btn.addClass('button-more-up');
		$menu.show();
	}
}

function explainExpression(inputObj, $expressionTip) {
	// TODO: performance tunning, only append the last key for keyup event
	var oldVal = j171.trim(j171(inputObj).val());
	var oldValMap = {};
	
	var genericType = inputObj.getAttribute('genericType');
	var lastType;
	if (genericType == 'number') {
		lastType = 'larger';
	} else {					
		lastType = 'contain';
	}
	if (oldVal.length > 0) {
		var vals = oldVal.split('&');
		for (var i = 0; i < vals.length; i++) {
			var c = vals[i].charAt(0);
			var key;
			if (c == '>') {
				oldValMap['larger'] = vals[i].substring(1);
				lastType = 'larger';
			} else if (c == '<') {
				oldValMap['less'] = vals[i].substring(1);
				lastType = 'less';
			} else if (c == '!') {
				oldValMap['not'] = vals[i].substring(1);
				lastType = 'not';
			} else {
				oldValMap[lastType] = vals[i];
				if (genericType == 'number') {
					j171(inputObj).val('>' + oldVal);
				}
			}
		}
	}
	$expressionTip.find('input').removeClass('input-hover');
	$expressionTip.find('input.' + lastType).addClass('input-hover');
	
	if (genericType == 'number') {
		$expressionTip.find('input.contain').val('').parent().hide().prev('label').hide();
		$expressionTip.find('input.not').val('').parent().hide().prev('label').hide();
		$expressionTip.find('input.larger').val(oldValMap['larger']).parent().show().prev('label').show();
		$expressionTip.find('input.less').val(oldValMap['less']).parent().show().prev('label').show();
	} else {
		$expressionTip.find('input.contain').val(oldValMap['contain']).parent().show().prev('label').show();
		$expressionTip.find('input.not').val(oldValMap['not']).parent().show().prev('label').show();
		$expressionTip.find('input.larger').val('').parent().hide().prev('label').hide();
		$expressionTip.find('input.less').val('').parent().hide().prev('label').hide();
	}
}
function addExpression(inputObj, flag) {
	var $expressionTip = j171(inputObj).closest('.expressionTip');
	var $targetInput = $expressionTip.data('target');
	
	var s = '';
	$expressionTip.find('input').each(function() {
		var val = j171(this).val();
		if (val != '') {
			if (s != '') {
				s += '&';
			}
			// flag is the comparasion flag: > < !
			s = s + this.getAttribute('flag') + j171(this).val();
		}
	});
	$targetInput.val(s);
}
function closeAdvanceSearchMenu(closeBtnObj) {
	var $menu = j171(closeBtnObj).closest('.searchTemplate');
	$menu.hide();
	var $btn = j171(closeBtnObj).closest('.jform').find('.button-more:first');
	$btn.removeClass('button-more-up');
	$btn.addClass('button-more-down');
}
function closeTipMenu(closeBtnObj) {
	var $menu = j171(closeBtnObj).closest('.expressionTip');
	$menu.hide();
}
function blurSearchInput(inputObj) {
	var $expressionTip = j171(inputObj).closest('.expressionTip');
	var $targetInput = $expressionTip.data('target');
	$targetInput.triggerHandler('blur');
}
function advanceSearch(btnObj, elementName) {
	closeAdvanceSearchMenu(btnObj);
	
	// build search condition and search
	var $searchTemplate = j171(btnObj).closest('.searchTemplate');
	var $form = $searchTemplate.data('searchBtn').closest('.jform');
	ajaxSubmit($searchTemplate, {
		includeUnCheckBox:false,
		data:{
			'newSearch':'true',
			'_type':'Map',
			
			// get the content from '_elementName'
			'_resultCode':'$element',
			'_elementName':elementName
		},
		beforeSend: function() {
			addLoading(j171('.jpageinfo table:last tr:first', $form));
		},
		success:function(data) {
			removeLoading(j171('.jpageinfo table:last tr:first', $form));
			
			var $oldPageinfo = $form.find('.jpageinfo:first');
			var $pageinfo = j171(data);
			$oldPageinfo.replaceWith($pageinfo);
			var $pagination = $form.find('.pageinfo-header .pagination:first');
			j171('.pageNo:first', $pagination).val(1);
			var totalCount = Number($pageinfo.attr('totalCount'));
			j171('.totalCount', $pagination).html(totalCount);
			if (totalCount == 0) {
				j171('.curPageStart', $pagination).html('0');
				j171('.curPageEnd', $pagination).html('0');
			} else {
				var curPageEnd = Number(j171('.curPageEnd', $pagination).html());
				if (curPageEnd > totalCount) {
					j171('.curPageEnd', $pagination).html(totalCount);
				}
			}
		}
	});
}
function resetAdvanceSearchForm(event, btnObj) {
	var $form = j171(btnObj).closest('.searchTemplate');
	$emements = $form.find('input,select,textarea');
	$emements.each(function() {
		j171(this).val('');
	});
}
function resetForm(btnObj) {
	var $form = j171(btnObj).closest('.jform');
	var $emements;
	if ($form.is('form') && !j171.browser.msie) {
		$emements = j171($form.get(0).elements);
	} else {
		$emements = $form.find('input,select,textarea');
	}
	$emements.each(function() {
		j171(this).val('');
	});
}

function showFileRemoveLink(obj) {
	var $obj = j171(obj);
	var filename = $obj.val();
	var $fileCtn = $obj.closest('.file_ctn');
	
	var $filename = $fileCtn.next('.file_ctn_old');
	var content = '<span>' + filename + '</span><a href="javascript:void(0)" onclick="j171(this).parent().html(\'\')"><em class="tinyClose"></em></a>';
	$filename.html(content);
	$fileCtn.find('.file_name').html('');
	$fileCtn.css('min-width', ($filename.width() + 20) + 'px');
}
function disable($obj) {
	$obj.addClass('disabled');
}
function enable($obj) {
	$obj.removeClass('disabled');
}
function showButtonMenu2(event, btnObj) {
	var $btnObj =  j171(btnObj);
	var $menu = j171('>.buttonMenu:first', $btnObj);
	
	if (!$btnObj.data('inited')) {
		$btnObj.data('inited', true);
		stopEvent(event);
		
		$btnObj.click(function(event){
			event.stopPropagation();
		});
		j171('html').click(function(event) {
			if ($menu.is(':visible')) {
				$menu.hide();
			}
		});
		// fix FIREFOX issue
		//j171('input[type=text]:first').focus().blur();
	}
	$menu.toggle();
}
function selectButtonMenu2($menubutton, selectIndex) {
	var $buttonCaption = j171('>.button-caption', $menubutton);
	var $menubuttonCtn = j171('>.buttonMenu', $menubutton);
	var $buttonMenuItem = j171('>span', $menubuttonCtn);
	$buttonMenuItem.eq(selectIndex).trigger('click');
	$menubuttonCtn.hide();
}
function showButtonMenu(event, btnObj) {
	var $btnObj =  j171(btnObj);
	var $menu = $btnObj.closest('.jmenubutton').children('.buttonMenu');

	var timeout = null;
	if (!$btnObj.data('inited')) {
		$btnObj.data('inited', true);
		stopEvent(event);

		$btnObj.click(function(event){
			event.stopPropagation();
		});
		j171('html').click(function(event) {
			if ($menu.is(':visible')) {
				$menu.hide();
				$btnObj.removeClass('button-more-up');
				$btnObj.addClass('button-more-down');
			}
		});
		
		var $caption = j171('>.button-caption', $btnObj);
		$caption.click(function() {
			var $menuItem = j171(this).data('menuItem');
			if ($menuItem) {
				$menuItem.trigger('click');
			}
		});
		
		// add callback function for each menu item
		j171('>span', $menu).click(function() {
			// bind the menu to menu caption
			$caption.html(j171(this).html()).data('menuItem', j171(this));
		});
		
		var hasMenuItem = j171('>span', $menu).length > 0;
		if (!hasMenuItem) {
			$menu.css('border', '0px');
		}
		
		// fix FIREFOX issue, (firefox highlight all the menu text, so switch the focus to another control
		//j171('input[type=text]:first').focus().blur();
	}
	
	if ($menu.is(':visible')) {
		$btnObj.removeClass('button-more-up');
		$btnObj.addClass('button-more-down');
		$menu.hide();
	} else {
		$btnObj.removeClass('button-more-down');
		$btnObj.addClass('button-more-up');
		$menu.show();
	}
}
/* search menu button - end */
function selectDateRange(event, btnObj, year, month, day) {
	var $menuButton = j171(btnObj).closest('.jmenubutton');
	var $date = $menuButton.nextAll('input:first');
	var hasInput = $menuButton.nextAll('.Wdate').length > 0;
	$menuButton.data('dateRange',[year, month, day]);
	
	if (year == 0 && month == 0 && day == 0) {		// clear the value for zero input
		$date.val('');
	} else {		
		var today = new Date();
		if (hasInput) {
			var val = $menuButton.nextAll('.Wdate').val();
			if (val != '') {
				var vals = val.split('-');
				today = new Date(Number(vals[0]), Number(vals[1]) - 1, Number(vals[2]));
			}
		}
		var dateRange = new Date(today.getFullYear() - year, today.getMonth() - month, today.getDate() - day);
		var s = dateRange.getFullYear() + '-' + (dateRange.getMonth() + 1) + '-' + dateRange.getDate();
		
		if (hasInput) {
			$date.val('>' + s);
		} else {
			$date.val(s);
		}
	}
	
	var $caption = j171('>.button-caption', $menuButton);
	$caption.html(j171(btnObj).html());
}
function updateDateRange(dp) {
	var btnObj = this;
	var $menuButton = j171(btnObj).prevAll('.jmenubutton');
	var range = $menuButton.data('dataRange');
	if (range) {
		selectDateRange(null, btnObj, range[0], range[1], range[2]);
	}
}
/* validation */
function isNumber(str) {
	for (var i = 0; i < str.length; i++) {
		var c = str.charAt(i);
		if (c >= '0' && c <= '9' || c == '.' || c == ',' || c =='-') {
		} else {
			return false;
		}
	}
	return true;
	//return !isNaN(parseFloat(n)) && isFinite(n);
}
/* validation - end */

/*  batch import page*/
function moveSortableItem( event, ui ) {
	var $draggable = j171(ui.draggable);
	var $draggableInput = j171('input', $draggable);
	if (ui.draggable.hasClass('cloneColumn')) {
		var top = ui.helper.position().top;
		var $li = j171(this).children('li');
		var isEmptyColumn = ui.draggable.hasClass('emptyColumn');
		if ($li.length == 0) {
			var $ctn = isEmptyColumn ? j171('<li style="position:relative" class="emptyColumn"></li>') : j171('<li style="position:relative"></li>');
			$draggableInput.val($draggableInput.attr('origValue'));
			var enabledContent = $draggable.html();
			$ctn.html(enabledContent + '<div class="tinyClose" onclick="removeSortableItem(this)"></div>').appendTo(j171(this));
		} else {			
			$li.each(function(index) {
				var liTop = j171(this).position().top;
				if (liTop > top || (index == $li.length - 1)) {
					var $ctn = isEmptyColumn ? j171('<li style="position:relative" class="emptyColumn"></li>') : j171('<li style="position:relative"></li>');
					$draggableInput.val($draggableInput.attr('origValue'));
					var enabledContent = $draggable.html();
					$ctn.html(enabledContent + '<div class="tinyClose" onclick="removeSortableItem(this)"></div>').insertBefore(j171(this));
					return false;
				}
			});
		}
		if (!isEmptyColumn) {
			ui.draggable.remove();
		}
	}
}
function removeSortableItem(iconObj) {
	var $li = j171(iconObj).parent();
	var $column1 = $li.parent();
	var $column3 = $column1.parent().next().children('ul');
	
	$li.children('div').remove();
	var content = $li.html();
	$li.remove();
	
	if (!$li.hasClass('emptyColumn')) {		
		var $removed = j171('<li style="position:relative" class="cloneColumn"></li>').html(content);
		j171('input', $removed).val('-1'); 
		$removed.appendTo($column3);
		$removed.draggable({helper: "clone", appendTo: $column1});
	}
}
/* batch import page - end */

/* util class */
/**
 * Get the i18n text
 * 
 * @param {} txt
 * @return {}
 */
function getText(txt) {
	var i18nTxt = g_text[txt];
	if (i18nTxt != null) {
		return i18nTxt;
	} else {
		return txt;
	}
}
function getModelKey(formObj) {
	var $form = j171(formObj);
	var action = $form.attr('action');
	var begin = action.indexOf('//');	// skip http://
	if (begin == -1) {
		begin = 0;
	} else {
		begin += 2;
	}
	if (g_base_site){
		begin += g_base_site.length;	// skip context path
	}
	var end = action.indexOf('.',begin);
	var s = action.substring(begin + 1, end);
	var modelKey = 'model.' + s.replace(/\//g, '.');
	return modelKey;
}
function getModelName(formObj) {
	var modelName = getModelKey(formObj);
	
	var i18nModelName = g_text[modelName];
	if (i18nModelName != null) {
		return i18nModelName;
	} else {
		// use current tab name if the tab existed
		var $curTab = j171(formObj).closest('.jtab');
		if ($curTab.length > 0) {
			var selected = $curTab.tabs("option", "selected");
			var $selectedTabHeader = $curTab.children('ul').children('li').eq(selected);
			return $selectedTabHeader.children('a').eq(0).text();
		} else {			
			var index = modelName.lastIndexOf('.');
			return modelName.substring(index + 1);
		}
	}
}

function parseURL(url) {
	// parameter
	var paramsIndex = url.lastIndexOf('?');
	var params = null;
	if (paramsIndex >= 0) {
		params = url.substring(paramsIndex + 1);
	} else {
		paramsIndex = url.length;
	}
	
	// extension
	var extensionIndex = url.lastIndexOf(".", paramsIndex - 1);
	// no extension --> wrong link
	var extension = url.substring(extensionIndex + 1, paramsIndex);
	
	// method
	// skip the '.'
	var methodIndex = url.lastIndexOf(".", extensionIndex - 1);
	// add, _add, _search, search, etc
	var method = null;
	if (methodIndex >= 0) {
		method = url.substring(methodIndex + 1, extensionIndex);
	} else {
		methodIndex = extensionIndex;
	}
	
	// path
	var path = url.substring(0, methodIndex);
	
	return {path:path, method:method, extension:extension, params:params};
}

function toURL(o) {
	var url = o.path;
	if (o.method != null) {
		url = url + '.' + o.method;
	}
	if (o.extension != null) {
		url = url + '.' + o.extension;
	}
	if (o.params != null) {
		url = url + '?' + o.params;
	}
	return url;
}

function toParameters(map) {
	var params = '';
	for (var key in map) {
		params += '&' + key + '=' + map[key];
	}
	return params;
}

/**
 * 
 * @param {} newMethod
 * @param {} url default url comes from the panel
 * @return {}
 */
function buildRequest(btn, newMethod, url, extraParams) {
	if (url == null || url == '') {
		// get the request url from main panel
		var $form = j171(btn).closest('.jform');
		url = $form.attr('action');
	}
	if (url != null && newMethod != null) {
		var o = parseURL(url);
		o.method = newMethod;
		if (extraParams) {
			if (o.params) {
				o.params += '&' + extraParams;
			} else {
				o.params = extraParams;
			}
		}
		return toURL(o);
	} else {
		return url;
	}
}

function fixPlaceholderDefect($placeholder) {
	if (j171.browser.msie) {
		if ($placeholder == null) {
			$placeholder = j171('.placeholder:not(input[type=password])');
		}
		$placeholder.bind('focus', function() {
			var $this = j171(this);
			if ($this.val() == $this.attr('placeholder')) {
				$this.css('color', '#666666');
				$this.val('');
			}
		});
		$placeholder.bind('blur', function() {
			var $this = j171(this);
			if ($this.val() == '') {
				$this.css('color', '#939393');
				$this.val($this.attr('placeholder'));
			}
		});
		$placeholder.each(function() {
			var $this = j171(this);
			if ($this.val() == '') {
				$this.css('color', '#939393');
				$this.val($this.attr('placeholder'));
			}
		});
	}
}
function initIndexPage(useTopMenu, hasPermission) {
	// <#--catch enter event for all search input container-->
	j171('body').on('keypress', '.searchInputCtn .jinput', function(event) {
		if (event.which == 13) {
			var $this = j171(this);
			$this.blur();
			var name = $this.attr('name');
			$this.closest('.searchInputCtn').find('[name$="search"]').click();
			$this.focus();			// TODO: focus the input again if search content refreshed
		}
	// <#-- TODO: check if there's performance issue -->
	}).on('keypress', function(event) {
		if (event.keyCode == 38 || event.keyCode == 40) {		// 38: key up, 40: key down
			// check if there's popup dropdown list
			if (j171('body').children('.ui-autocomplete:visible').length > 0) {
				return;
			}
			
			// move the next/previous row
			var $activeTab = getActiveDom();
			var $pageinfo = $activeTab.find('.jpageinfo');
			if ($pageinfo.length > 0) {
				var index = $activeTab.data('selectedPageinfoIndex');
				if (!index) {
					index = 0;
				}
				$pageinfo = $pageinfo.eq(index);
				var $curTr = $pageinfo.find('.current');
				var $tr;
				if (event.keyCode == 38) {
					$tr = $curTr.prev('tr');
				} else {					
					$tr = $curTr.next('tr');
				}
				if ($tr.length > 0) {
					var showWinBtn = 'true' == $pageinfo.attr('showWinBtn');
					loadChildContainer($tr, true, showWinBtn);
					var top = $tr.position().top - 100;
					if (top <= 0) {
						top = 0;
					}
					$tr.closest('.fht-tbody').animate({scrollTop: top}, 10);
				}
			}
		}
	}).on('focus','input',function(event){
		j171(this).parent('.jbox').addClass('focus');
	}).on('blur','input',function(event){
		j171(this).parent('.jbox').removeClass('focus');
	});
	
	// show 'go to top' button
	j171(window).scroll(function () {
		if (j171(window).scrollTop() > 200) {
			j171('#gotoTop').show();
		} else {
			j171('#gotoTop').hide();
		}
	});
	
	// zoom in / out
	j171(window).on('resize',function(){
		onZoomChange(j171('#accessory_zoom'));
	})
	
	/*
	// comment it because it affects the document height when switching the tab
	var top = 0;
	if (useTopMenu) {		
		top = 26;
	}
	j171(document).on('documentResize',function(){
		j171('#mainCtn').height(j171(document).height() - top);	// <#--resize the size when content is change-->
	})
	j171('#mainCtn').height(j171(document).height() - top);
	j171('#g_mainPanel').on('select.tabs', function() {		// <#--resize to the normal size when switching the main table-->
		j171('#mainCtn').height(j171(window).height() - top);
	});*/
	when('j171.fn.tabs', function() {
		bindMainTab(hasPermission);
	});
}

function onZoomChange(o) {
	var s = o.scale;
    if(s && s != 1){
    	showTip('您的浏览器处于缩放状态，会导致网页显示不正常，您可以键盘按"Ctrl+数字0"组合键恢复到初始状态');
    }
}
function centerShow(obj) {
	var $obj = j171(obj);
	var width = $obj.outerWidth(true);
	var height = $obj.outerHeight(true);
	if (j171.browser && j171.browser.msie && j171.browser.version == "6.0") {
		$obj.css({
					"position" : "absolute",
					"display" : "block",
					visibility : "visible"
				});
		var ie6Style = function() {
			$obj.css({
						"left" : Math
								.floor((j171(window).width() - width)
										/ 2),
						"top" : Math
								.floor((j171(window).height() - height)
										/ 2)
								+ j171(window).scrollTop()
					});
		};
		ie6Style();
		j171(window).resize(function() {
					ie6Style();
				}).scroll(function() {
					ie6Style();
				});
	} else {
		var $centerBox = j171("#ffutil-center-box");
		if ($centerBox.size() == 0) {
			$centerBox = j171("<div id='#ffutil-center-box' />");
			$centerBox.css({
						"position" : "fixed",
						"top" : "50%",
						"left" : "50%",
						"z-index" : 9999
					});
			j171("body").append($centerBox);
		}
		$centerBox.append($obj);
		$obj.css({
					"position" : "absolute",
					"left" : -Math.floor(width / 2),
					"top" : -Math.floor(height / 2),
					"display" : "block",
					visibility : "visible"
				});
	}
}
/**
 * Show the object in the fixed position
 * 
 * @param {}
 *            css
 * @return {}
 */
function posShow(obj, css) {
	if (j171.browser.msie && j171.browser.version == "6.0") {
		j171.extend(css, {
					"position" : "absolute",
					"display" : "block"
				});

		var tempCss = {};
		j171.extend(tempCss, css);
		var height = j171(obj).height();
		var setPos = function() {
			if (css["bottom"] != "undefined") {
				tempCss["bottom"] = parseInt(css["bottom"]);
				tempCss["zoom"] = 1;
				j171(obj).css(tempCss);
				tempCss["zoom"] = 0;
			}
			j171(obj).css(tempCss);
		};

		setPos();

		j171(window).scroll(function() {
					setPos();
				}).resize(function() {
					setPos();
				});
	} else {
		j171.extend(css, {
					"position" : "fixed",
					"display" : "block"
				});
		j171(obj).css(css);
	}
}

/** 
 * Show Container, TODO: merger with 'Container function'
 */
j171.fn.extend({
	center : function () {
		var $obj = j171(this);
		var width = $obj.outerWidth(true);
		var height = $obj.outerHeight(true);
		var left = Math.floor((j171(window).width() - width) / 2);
		var top = Math.floor((j171(window).height() - height) / 2) + j171(document).scrollTop();

		$obj.css({'left': left, 'top': top});
	},
	centerShow : function() {
		centerShow(this);
		return this;
	},
	posShow : function(css) {
		posShow(this);
		return this;
	}
});
function showTip(text, width) {
	// TODO: use tip style
	showSuccess(text, width);
}
function showSuccess(text, width) {
	var $okTip = j171("#okTip");
	if (!width) {
		width = 300;
	}
	if ($okTip.size() == 0) {
		$okTip = j171('<div id="okTip" class="alert-tip alert-ok"><div></div><span></span></div>');
		j171("body").append($okTip);

	}

	$okTip.show();

	$okTip.find("div").html(text);
	$okTip.find("div").width(width - 80);

	$okTip.find("span").width(width).height($okTip.find("div")
			.outerHeight());

	$okTip.width(width);
	$okTip.height($okTip.find("div").outerHeight());

	posShow($okTip, {right: 5, bottom: 5});

	var _tipTime = $okTip.data('_tipTime');
	clearTimeout(_tipTime);
	_tipTime = setTimeout(function() {
		$okTip.fadeOut("slow");
	}, 2000);
	$okTip.data('_tipTime', _tipTime);

	return $okTip;
}
function showError(text, width, left, top, time) {
	var $errTip = j171("#errTip");
	if (!width) {
		width = 300;
	}
	if ($errTip.size() == 0) {
		$errTip = j171('<div id="errTip" class="alert-tip alert-err"><div></div><span></span></div>');
		j171("body").append($errTip);
	}

	$errTip.show();

	$errTip.find("div").html(text);

	$errTip.width(width);
	$errTip.height($errTip.find("div").outerHeight());
	$errTip.find("div").width(width - 80);
	$errTip.find("span").width(width).height($errTip.find("div")
			.outerHeight());
	if (left || top) {
		$errTip.css("top", top);
		$errTip.css("left", left);
		$errTip.show();
	} else {
		centerShow($errTip);
	}
	
	var _tipTime = $errTip.data('_tipTime');
	clearTimeout(_tipTime);
	var closeFunc = function(event) {
		if (event) {			
			var $target = j171(event.target);
			// click on the outside of the error container
			if ($target.closest('#errTip').length > 0) {
				return ;
			}
		}
		
		$errTip.fadeOut("slow");
		j171(document).off('mouseup', closeFunc);
	}
	if (!time) {
		time = 3000;
	}
	_tipTime = setTimeout(closeFunc, time);
	j171(document).on('mouseup', closeFunc);
	$errTip.data('_tipTime', _tipTime);

	return $errTip;
}
(function(j171){
	/**
	 * Show confirm message
	 * 
	 * parameters:
	 * String title, String message, Function ok, Array buttons
	 */
	j171.confirm = function(params){
		if(j171('#confirmOverlay').length){
			// A confirm is already shown on the page:
			return false;
		}
		
		// add default button
		if (!params.buttons && params.ok) {
			params.buttons = {};
			params.buttons[getText('确认')] = {
				'class'	: 'blue',
				'action': function() {
					params.ok();
				}
			};
			params.buttons[getText('取消')] = {
				'class'	: 'gray',
				'action': function(){
					if (params.cancel) {
						params.cancel();
					}
				}
			};
		}
		
		var buttonHTML = '';
		j171.each(params.buttons,function(name,obj){
			// Generating the markup for the buttons:
			buttonHTML += '<a href="#" class="button '+obj['class']+'">'+name+'<span></span></a>';
			
			if(!obj.action){
				obj.action = function(){};
			}
		});
		
		var markup = [
			'<div id="confirmOverlay">',
			'<div id="confirmBox">',
			'<h1>',params.title,'</h1>',
			'<p>',params.message,'</p>',
			'<div id="confirmButtons">',
			buttonHTML,
			'</div></div></div>'
		].join('');
		
		j171(markup).hide().appendTo('body').fadeIn();
		
		var buttons = j171('#confirmBox .button'),
			i = 0;

		j171.each(params.buttons,function(name,obj){
			buttons.eq(i++).click(function(){
				// Calling the action attribute when a
				// click occurs, and hiding the confirm.
				obj.action();
				j171.confirm.hide();
				return false;
			});
		});
	}
	
	/**
	 * Show message in the dialog
	 * 
	 * required parameters:
	 * String title, String message, Function ok
	 * Optional Parameters:
	 * buttons, width, height, url, data
	 */
	j171.exdialog = function(params) {
		if (!params.buttons) {
			params.buttons = [{
				text: getText('确认'),
				click: function() {
					var $dialog = j171(this);
					var ret = params.ok($dialog);
					if (ret != false) {
						$dialog.dialog("close");
					}
				}
			},{
				text: getText('取消'),
				click: function() {
					var $dialog = j171(this);
					$dialog.dialog("close");
				}
			}]
		}
		
		var $dialogCtn = j171('#dialogCtn');
		if ($dialogCtn.length == 0) {
			j171('body').append('<div id="dialogCtn"></div>');
			$dialogCtn =  j171('#dialogCtn');
		}
		$dialogCtn.dialog('destroy');
		var $dialog = $dialogCtn.dialog({
			modal: true,
			title: params.title,
			width: params.width||1010,
			height: params.height,
			buttons: params.buttons
		});
		
		if (params.url) {
			addLoading($dialog);
			var url = params.url;
			j171.ajax({
				url: url,
				type: 'post',
				data: params.data,
				success: function(data) {
					removeLoading($dialog);
					$dialog.html(data);
					var e = new j171.Event('load');
					$dialog.trigger(e);
				}
			});
		} else {
			$dialog.html(params.message);
		}
		return $dialog;
	}

	j171.confirm.hide = function(){
		j171('#confirmOverlay').fadeOut(function(){
			j171(this).remove();
		});
	}
	
	j171.fn.log = function (msg) {
		if (j171.browser.msie) {
		} else {
			console.log("%s: %o", msg, this);
		}
	    return this;
	};
})(j171);

/**
 * Selection cursor
 */
(function(j171) {
    j171.fn.hasScrollBar = function() {
        return this.get(0).scrollHeight > this.height();
    }
    
    j171.fn.setCursorPosition = function(position){
    	var $this = j171(this);
        if($this.lengh == 0) return $this;
        return $this.setSelection(position, position);
    }
    j171.fn.setSelection = function(selectionStart, selectionEnd) {
    	var $this = j171(this);
    	if($this.lengh == 0) return $this;
        input = $this[0];

        if (input.createTextRange) {
            var range = input.createTextRange();
            range.collapse(true);
            range.moveEnd('character', selectionEnd);
            range.moveStart('character', selectionStart);
            range.select();
        } else if (input.setSelectionRange) {
            input.focus();
            input.setSelectionRange(selectionStart, selectionEnd);
        }

        return $this;
    }
    j171.fn.focusEnd = function(){
    	var $this = j171(this);
    	var val = $this.val();
    	if (val) {		
    		$this.setCursorPosition(val.length);
    	}
    }
})(j171);

/**
 * Cookie
 */
(function(j171) {
	j171.cookie = function(name, value, options) {
		if (typeof value != 'undefined') {
			options = options || {};
			if (value === null) {
				value = '';
				options = j171.extend({}, options);
				options.expires = -1;
			}
			var expires = '';
			if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
				var date;
				if (typeof options.expires == 'number') {
					date = new Date();
					date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
				} else {
					date = options.expires;
				}
				expires = '; expires=' + date.toUTCString();
			}
			var path = options.path ? '; path=' + (options.path) : '';
			var domain = options.domain ? '; domain=' + (options.domain) : '';
			var secure = options.secure ? '; secure' : '';
			document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
		} else {
			var cookieValue = null;
			if (document.cookie && document.cookie != '') {
				var cookies = document.cookie.split(';');
				for (var i = 0; i < cookies.length; i++) {
					var cookie = jQuery.trim(cookies[i]);
					if (cookie.substring(0, name.length + 1) == (name + '=')) {
						cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
						break;
					}
				}
			}
			return cookieValue;
		}
	};
})(j171);

/**
 * Container function:
 * 
 * hide / autoClose
 */
(function(j171){
	var Ctn = function(element) {
		var $element = j171(element);
		var obj = this;

		/**
		 * hide a container, for example: hide header menu
		 * 
		 * @param lockIt default status is locked or unlocked
		 */
		this.autoHide = function(lockIt) {
			var $autoHideCtn = $element.parent('div');
			var inited = $autoHideCtn.hasClass('autoHideCtn');
			if (inited) {
				return ;
			}
			
			$autoHideCtn = j171('<div class="autoHideCtn"></div>');
			$element.wrap($autoHideCtn);
			$autoHideCtn = $element.parent();
			var $autoHideBar = j171('<div class="autoHide"><div class="autoHideBg"></div>'
					+ '<div class="autoHandleCtn"><em class="lock"></em><em class="handle"></em></div></div>');
			$autoHideCtn.append($autoHideBar);
			
			var oldHeight = $element.height();
			if (!lockIt) {		
				$element.height(0);
				$element.hide();
			}
			
			var leaveTime;
			var isLock = !lockIt;
			$autoHideCtn.mouseenter(function() {
				if (isLock) {
					return;
				}
				if (leaveTime) {
					clearTimeout(leaveTime);
				}
				$element.show();
				$element.animate({height:oldHeight}, 200);
			}).mouseleave(function() {
				if (isLock) {
					return;
				}
				leaveTime = setTimeout(function() {
					$element.animate({height:0}, 200, function() {
						$element.hide();
					});
				}, 400);
			});
			
			var $lockBg = $autoHideBar.find('.autoHideBg');
			var $lockIcon = $autoHideBar.find('.lock');
			var changeLockStatus = function() {
				if (isLock) {
					isLock = false;
					$element.css('position', 'fixed');
					$lockIcon.removeClass('unlock').addClass('lock');
					$lockBg.show();
					$lockIcon.next('.handle').show();
				} else {
					isLock = true;
					$element.css('position', 'relative');
					$lockIcon.removeClass('lock').addClass('unlock');
					$lockBg.hide();
					$lockIcon.next('.handle').hide();
				}
			};
			$lockIcon.click(changeLockStatus);
			changeLockStatus();
		};
		
		this.autoClose = function() {
			$element.click(function(event) {
				event.stopImmediatePropagation();
			});
			setTimeout(function() {
				j171(document).one('click', function() {
					var $closeIcon = $element.children('.close');
					if ($closeIcon.length > 0) {
						$closeIcon.click();
					} else {						
						$element.hide();
					}
				});
			}, 100);
		};
		
		// Private method - can only be called from within this object
		var privateMethod = function(){
			j171.log('private method called!');
		};
	};

	j171.fn.ctn = function() {
		this.each(function() {
			var element = j171(this);
			if (element.data('ctn')) return;
			var ctn = new Ctn(this);
			element.data('ctn', ctn);
		});
		return j171(this).data('ctn');
   };
})(j171);

/**
 * Get/Set property to json object
 */
var Ognl = {
	get : function(obj, p) {
	  if (!p) {
		  return null;
	  }
	  p = p.split('.');
	  for (var i = 0, len = p.length; i < len - 1; i++) {
		  if (obj) {			  
			  obj = obj[p[i]];
		  } else {
			  return null;
		  }
	  }
	  if (obj) {
		  return obj[p[len - 1]];
	  } else {
		  return null;
	  }
	},
	set : function(obj, p, value) {
	  p = p.split('.');
	  for (var i = 0, len = p.length; i < len - 1; i++)
	    obj = obj[p[i]];
	  obj[p[len - 1]] = value;
	}
};

String.prototype.endsWith = function(s) {
	if (s == null || s == "" || this.length == 0 || s.length > this.length)
		return false;
	if (this.substring(this.length - s.length) == s)
		return true;
	else
		return false;
	return true;
}
String.prototype.startsWith = function(s) {
	if (s == null || s == "" || this.length == 0 || s.length > this.length)
		return false;
	if (this.substr(0, s.length) == s)
		return true;
	else
		return false;
	return true;
}


var Notifier = {
	// Returns "true" if this browser supports notifications.
	hasSupport : function() {
		if (window.webkitNotifications) {
			return true;
		} else {
			return false;
		}
	},
	// Request permission for this page to send notifications. If allowed,
	// calls function "cb" with true.
	requestPermission : function(cb) {
		window.webkitNotifications.requestPermission(function() {
			if (cb) {
				cb(window.webkitNotifications.checkPermission() == 0);
			}
		})
	},
	// Popup a notification with icon, title, and body. Returns false if
	// permission was not granted.
	notify : function(icon, title, body) {
		if (window.webkitNotifications.checkPermission() == 0) {
			var popup = window.webkitNotifications.createNotification(icon, title, body);
			popup.show();
			return true;
		}
		return false;
	}
}

function collision($div1, $div2) {
	var x1 = $div1.offset().left;
	var y1 = $div1.offset().top;
	var h1 = $div1.outerHeight(true);
	var w1 = $div1.outerWidth(true);
	var b1 = y1 + h1;
	var r1 = x1 + w1;
	var x2 = $div2.offset().left;
	var y2 = $div2.offset().top;
	var h2 = $div2.outerHeight(true);
	var w2 = $div2.outerWidth(true);
	var b2 = y2 + h2;
	var r2 = x2 + w2;
	
	if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) return false;
	return true;
}
function toNumber(str) {
	if (!str) {
		return 0;
	}
	str = '' + str;
	var nStr = '';
	for (var i = 0; i < str.length; i++) {
		var c = str.charAt(i);
		if (c >= '0' && c <= '9' || c == '.') {
			nStr += c;
		}
	}
	return Number(nStr);
}
function format(s) {
	for (var i = 0; i < arguments.length - 1; i++) {
		var reg = new RegExp("\\{" + i + "\\}", "gm");
		s = s.replace(reg, arguments[i + 1]);
	}
	return s;
}
/* util class - end */